Uncaught typeerror cannot read property 'top' of undefined error

I get uncaught typeerror cannot read property ‘top’ of undefined error when I run a JSFiddle working code in my application. The JSFiddle fine without any errors.

I can understand that the line in my code mentioned below ```

scrollTop = $('.highlighted:last', panel).position().top;

is unable to find the `highlighted` class as
console.log (“Check for highlighted in click handler:” +highlighted);

doesn't shows highlighted class getting applied to the document in my webapp. I suspect it is because of the following lines of code I am adding in my code:

for (var i = 0; i < length; i++) {
html = html.replace(new RegExp(records[i].concept_text, ‘ig’), ‘’ + records[i].concept_text + ‘’);
}


and when I check the console.log("How many span tags you are noticing here?: " + html);, I see the words (concept_text) are surrounded by two span tags like the following:

MYELOMA


And somewhere I noticed even three span tags.
 
 Could it be the reason that the regular expression mentioned in the code 

var
highlighted = content.replace(
regExp,
‘$1$2$3’
);


 isn't applying the `span` tags because of already present two and three span tags?

Here is my code :  

 
      this.myDocument = function (data_) {
    
            var source = {
                localdata: data_,
                datafields: [{
                    name: 'doc_content',
                    type: 'string'
                }, {
                    name: 'concept_text',
                    type: 'string'
                }, {
                    name: 'start',
                    type: 'int'
                }, {
                    name: 'stop',
                    type: 'int'
                }],
                datatype: "array"
    
            };
    
    
            var dataAdapter = new $.jqx.dataAdapter(source, {
    
                loadComplete: function (records) {
                    var html;
                    var color = '#FF0000';
    
                    //Get data
                    var records = dataAdapter.records;
                    var length = records.length;
                    console.log("Checking Length: "+length);// Outputs 5 
                    for (var i = 0; i < length; i++) {
                    console.log("checking Concepts here: " +records[i].concept_text);
                    }
    				html = "<div style='margin: 10px;'><pre>" + records[1].doc_content + "</pre></div>";
    				
                    for (var i = 0; i < length; i++) {
    
                      html = html.replace(new RegExp(records[i].concept_text, 'ig'), '<span style="color:' + color + ';">' + records[i].concept_text + '</span>');
                    }
                     console.log("How many span tags you are noticing here?: " + html);
                    $("#docContentPanel").html(html);
                },
                loadError: function (xhr, status, error) { },
                beforeLoadComplete: function (records) {
    
                }
            });
            // perform data binding
            dataAdapter.dataBind();
    
            
            $("#myPanel").jqxGrid({
    
                source: dataAdapter,
                width: '122',
                height: '170',
    
                columns: [{
                    text: 'Concept(s)',
                    datafield: 'concept_text',
                    cellsalign: 'center',
                    width: 100
                }, {
                    text: 'Note Content',
                    datafield: 'doc_content',
                    hidden: true
                }
    
                ]
            });
    
            var panel = $("#docContentPanel");
            
            var content = panel.html();
    
          
    
            panel.jqxPanel({
                width: '750',
                height: '500',
                scrollBarSize: 20
            });
    
    
            $("#myPanel").on('cellclick', function (event) {
    
               
                  
                var value = event.args.value;
      
    			  // Use a regular expression to account for the beginning/end of the
    			  // input, arbitrary whitespace (including line feeds) as well as
    			  // adjacent tags
    			  var regExp = new RegExp('(^|>|\\s)(' + value + ')($|<|\\s)', 'g');
    			  
    			  var scrollTop;
    
    			  var highlighted = content.replace(
    				regExp,
    				'$1<span class="highlighted">$2</span>$3'
    			  );
    			  
    			  console.log ("Check for highlighted in click handler:" +highlighted);
    			  panel.jqxPanel('clearcontent');
    			  panel.jqxPanel('append', highlighted);
    			  
    			  // Get the offset of the last highlighted word relative
    			  // to the panel parent
    			  scrollTop = $('.highlighted:last', panel).position().top;
    			  
    			  // Use the jqxPanel API to scroll to that word
    			  panel.jqxPanel('scrollTo', 0, scrollTop);
    
    
                
    
    
            });
    
        }; // End of myDocument function


Please advise. The original author of the above code who helped me comes from [this post.](https://www.sitepoint.com/community/t/dealing-with-character-offsets/236144/7)

No, the regular expression does account for that. Could you set up a fiddle with some dummy data (i.e. that doesn’t rely on an external data_ parameter)?

Anyway, you can catch the case when there is no match to be highlighted like

var last = $('.highlighted:last', panel);
  
if (!last.length) return;
  
scrollTop = last.position().top;
panel.jqxPanel('scrollTo', 0, scrollTop);

… which you should probably do anyway.

Hi @m3g4p0p,

Sure, I will get back to you with the JSFiddle soon. In the mean while, I have few questions,

  1. Could you explain me how is the regular expression working $1<span class="highlighted">$2</span>$3 in the above code?

  2. Also, how the positions are getting calculated accurately, I mean, for example, in this JSFiddle, I have Patient word in the content two times (one at the first line and one at the last line), why does it takes me to the last word? Thanks

Those $n parameters hold the values of the corresponding (capturing parentheses), so that in this regular expression

var regExp = new RegExp('(^|>|\\s)(' + value + ')($|<|\\s)', 'g');

for example $1 would either be a > or a white space character (whichever precedes value), or empty if value was at the beginning of the input. As always, there’s a good introduction to regular expressions at the MDN!

I actually commented on this in the code I posted over at your other thread… ;-)

// Get the offset of the last highlighted word relative
// to the panel parent
scrollTop = $('.highlighted:last', panel).position().top;
  
// Use the jqxPanel API to scroll to that word
panel.jqxPanel('scrollTo', 0, scrollTop);

Hey @m3g4p0p,

Thanks for the answers. Sorry for the delay in providing the JSFiddle you requested. I created a JSFiddle which will basically show you the flow of the work that is happening. So, in my JSFiddle here ( Right now the highlight functionality isn’t working here but it will give you and idea what’s happening). So, there are 3 jqxWidgets I am using. When a user clicks on any cell of firstjqxgrid, it will open the secondjqxgrid and jqxPanel at the same time. And when a user clicks on any cell value of secondjqxgrid' ( Concepts` column), it is supposed to highlight the content in the text of the jqxPanel as you mentioned in your previous working fiddle here. Let me know if you have any problem in understanding the flow or need more information.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.