Mike Barbaro Mike Barbaro - 6 months ago 9
Javascript Question

JSON and jQuery Search

I keep on getting the following error when I use the following code. Any help is appreciated. I have been stuck on this for quite awhile.

tipuedrop.js:60 Uncaught TypeError: Cannot read property 'search' of undefined

function getTipuedrop($obj) {
if ($obj.val()) {
var c = 0;
for (var i = 0; i < tipuedrop_in.pages.length; i++) {
var pat = new RegExp($obj.val(), 'i');
if ((tipuedrop_in.pages[i].name.search(pat) != -1 || tipuedrop_in.pages[i].description.search(pat) != -1) && c < set.show) {
if (c == 0) {
var out = '<div class="tipue_drop_box"><div id="tipue_drop_wrapper">';
}
out += '<a href="' + tipuedrop_in.pages[i].name + '"';
if (set.newWindow) {
out += ' target="_blank"';
}
out += '><div class="tipue_drop_item"><div class="tipue_drop_left"><img src="' + tipuedrop_in.pages[i].name + '" class="tipue_drop_image"></div><div class="tipue_drop_right">' + tipuedrop_in.pages[i].name + '</div></div></a>';
c++;
}
}
if (c != 0) {
out += '</div></div>';
$('#tipue_drop_content').html(out);
$('#tipue_drop_content').fadeIn(set.speed);
}
} else {
$('#tipue_drop_content').fadeOut(set.speed);
}
}


Here's the whole Javascript:

(function($) {

$.fn.tipuedrop = function(options) {

var set = $.extend( {

'show' : 3,
'speed' : 300,
'newWindow' : false,
'mode' : 'static',
'contentLocation' : 'tipuedrop/tipuedrop_content.json'

}, options);

return this.each(function() {

var tipuedrop_in = {
pages: []
};
$.ajaxSetup({
async: false
});

if (set.mode == 'json')
{
$.getJSON(set.contentLocation)
.done(function(json)
{
tipuedrop_in = $.extend({}, json);
});
}

if (set.mode == 'static')
{
tipuedrop_in = $.extend({}, tipuedrop);
}

$(this).keyup(function(event)
{
getTipuedrop($(this));
});

function getTipuedrop($obj)
{
if ($obj.val())
{
var c = 0;
for (var i = 0; i < tipuedrop_in.pages.length; i++)
{
var pat = new RegExp($obj.val(), 'i');
if ((tipuedrop_in.pages[i].name.search(pat) != -1 || tipuedrop_in.pages[i].description.search(pat) != -1) && c < set.show)
{
if (c == 0)
{
var out = '<div class="tipue_drop_box"><div id="tipue_drop_wrapper">';
}
out += '<a href="' + tipuedrop_in.pages[i].name + '"';
if (set.newWindow)
{
out += ' target="_blank"';
}
out += '><div class="tipue_drop_item"><div class="tipue_drop_left"><img src="' + tipuedrop_in.pages[i].master_image + '" class="tipue_drop_image"></div><div class="tipue_drop_right">' + tipuedrop_in.pages[i].name + '</div></div></a>';
c++;

console.log(tipuedrop_in.pages[i].name);
console.log(tipuedrop_in.pages[i].description);
}
}
if (c != 0)
{
out += '</div></div>';
$('#tipue_drop_content').html(out);
$('#tipue_drop_content').fadeIn(set.speed);
}
}
else
{
$('#tipue_drop_content').fadeOut(set.speed);
}
}

$('html').click(function()
{
$('#tipue_drop_content').fadeOut(set.speed);
});

});
};

})(jQuery);

Answer

Your JSON array has an element without the name and description attributes. It is element with id "dae04696-2acb-4972-a471-1b873e2a8d4f" at index 322:

{
    "fees":[],"variations":[],
    "available_for_pickup":true,
    "available_online":false,
    "visibility":"PUBLIC",
    "id":"dae04696-2acb-4972-a471-1b873e2a8d4f",
    "type":"NORMAL"
}

So your code will raise an error in the following statement because you try to use a String method (search) on the undefined name attribute:

if ((tipuedrop_in.pages[i].name.search(pat) != -1 || ....

So prefix in that if an additional condition to make sure the attribute exists, and do the same with description.

if ((tipuedrop_in.pages[i].name 
             && tipuedrop_in.pages[i].name.search(pat) != -1 
       || tipuedrop_in.pages[i].description 
             && tipuedrop_in.pages[i].description.search(pat) != -1) 
   && c < set.show) {
       ...

Note that converting to String explicitly (with String(tipuedrop_in.pages[i].name)) will also remove the error condition, because it will render "undefined" (string) when the name property does not exist.

However, this has a side-effect:

When you search by a sub-string of "undefined", like "fine", you will get a match with this undefined name, which probably is not what you want as behaviour.

Comments