Looping through API using jQuery each - javascript

I am trying to use the Marvel API to display a list of events a character has been involved in. Here is my script:
$(".heroSubmit").click(function() {
var heroName = $(".hero").val();
$.getJSON("http://gateway.marvel.com:80/v1/public/characters?name=" + heroName + "&apikey=", function (json) {
$(".name").html(json.data.results[0].name);
$(".description").html(json.data.results[0].description);
$(".image").attr("src", json.data.results[0].thumbnail.path + "/detail.jpg");
$(".comics").html(json.data.results[0].comics.available);
$.each( json.data.results[0].events.items, function(i, item) {
$(".events").html("<li>" + item.name + "</li>");
});
});
Everything works fine except for the each section. Right now, it is only displaying the last event name (item.name). I need for all of the events to display.

This is because you rewrite events' content in each iteration. To avoid this replace html() with append():
$.each( json.data.results[0].events.items, function(i, item) {
$(".events").append("<li>" + item.name + "</li>");
});

Related

mcautocomplete disappearing over slickgrid

I added mcautocomplete to my slickgrid. if I check some of the checkboxes mcautocomplete table is not visible anymore on slickgrid. Please check the pic.
How do i make sure that my autocomplete options are visible over my slickgrid?
$.widget('custom.mcautocomplete', $.ui.autocomplete, {
_create: function () {
this._super();
this.widget().menu("option", "items", "> :not(.ui-widget-header)");
},
_renderMenu: function (ul, items) {
var self = this,
thead;
if (this.options.showHeader) {
table = $('<div class="ui-widget-header" style="width:100%"></div>');
$.each(this.options.columns, function (index, item) {
table.append('<span style="font-weight:bold;background-color:#EEE8AA;padding:0 4px;float:left;width:' + item.width + ';">' + item.name + '</span>');
});
table.append('<div style="clear: both;"></div>');
ul.append(table);
}
$.each(items, function (index, item) {
self._renderItem(ul, item);
});
},
_renderItem: function (ul, item) {
var t = '',
result = '';
$.each(this.options.columns, function (index, column) {
t += '<span style="background-color:#ADD8E6;padding:0 4px;float:left;width:' + column.width + ';">' + item[column.valueField ? column.valueField : index] + '</span>'
});
result = $('<div></div>')
.data('ui-autocomplete-item', item)
.append('<div class="mcacAnchor">' + t + '<div style="clear: both;"></div></div>')
.appendTo(ul);
return result;
}
});
You can try z-index (this can be complex and all comes down to the priority of the container elements), but I have found that the structure of some javascript controls are simply not compatible with SlickGrid.
(not saying that mcautocomplete is not compatible, with the right tweaks, but it MAY not be).
For example, I was using 'chosen' for dropdowns, but as it used table elements that would not play well with the slickgrid infrastructure, I had to abandon that for 'select2'. There is a 'select2' example in the 6pac github repository, and I think select2 has an autocorrect mode. Might be worth a try.

Jquery - custom HTML for template - strange behavior

var $template;
$.get('/templates/searchTemplate.tmpl', function(HTMLres) {
$template = $(HTMLres);
});
$.each(data.results, function(key, value) {
$template.find('button').off().on('click', function() { console.log('you clicked me') });
$template.find('.media-body > strong').html(value.firstname + ' ' + value.lastname);
$template.find('.email').html(value.mail);
$template.find('.phone').html(value.phone);
$template.find('.age').html(value.age);
$('#searchRsults').append($template);
});
When I try to use this code instead of having the template file to be Appended to the UL element, this will clear the previous append and append the next result to the UL element.
The template file is just a -> <LI> </LI> with some spans.
Note that if I put the |$.get (template) in the $.each part of the code everything works like it supposed to be all the <LI> </LI> element are appended one after another.
But doing so it makes a lot of request for the template file. On every iteration actually.
Even if I use the .DONE after the Ajax request still the result is the same the <LI> </LI> gets overwritten not appended
You should put the each() inside the success callback so the $template will be available, else you're trying to use the $template when it's not returned yet from the asynchronous HTTP (Ajax) request :
var $template;
$.get('/templates/searchTemplate.tmpl', function(HTMLres) {
$template = $(HTMLres);
$.each(data.results, function(key, value) {
$template.find('button').off().on('click', function() { console.log('you clicked me') });
$template.find('.media-body > strong').html(value.firstname + ' ' + value.lastname);
$template.find('.email').html(value.mail);
$template.find('.phone').html(value.phone);
$template.find('.age').html(value.age);
$('#searchRsults').append($template);
});
});
Take a look to How do I return the response from an asynchronous call?.
Hope this helps.
function getResults(searchTerm){
return $.get("/api/search", { 'searchFor': keyword });
}
function getTemplate(){
return $.get('/templates/searchTemplate.tmpl')
}
$.when(getResults(keyword), getTemplate())
.done(function(result1, result2){
$('ul#searchRsults').empty();
if (result1[0].results.indexOf('no results') != 0) {
$.each(result1[0].results, function(key, value) {
var $template = $(result2[0]);
$template.find('.img-avatar').html(img);
$template.find('button').off().on('click', function() { console.log('you clicked me') });
$template.find('.media-body > strong').html(value.firstname + ' ' + value.lastname);
$template.find('.email').html(value.mail);
$template.find('.phone').html(value.phone);
$template.find('.age').html(value.age);
$('#searchRsults').append($template);
});
}
})
after some read - I ended with this solution, in chrome console the request for template is made only once. Hope this helps sombady

Unobtrusive jQuery Set Attributes Before Append - Is More Effecient Syntax Possible?

The basic process for this code is:
$.get a Mustache template
$.getJSON some data from the API
Then the code below to process on the client
$.each(data, function (i, item) {
item.Date = internationalDateTime(item.Date );
var html = Mustache.to_html(template, item);
var $html = $(html);
$html.find('input[name=btnView]').attr('onclick', 'loadView(' + item.Id + ')');
$('#list-container').append($html);
});
Is there a better way (read more succinct I guess) of doing this without the need for the $html variable?
Not wanting to obsess over "one liners" in my code but it just looks a bit wrong to me.
before adding your html to the DOM, you can do this:
$(document).on("click", "#list-container input[name=btnView][itemId]", function(){
loadView($(this).attr("itemId"));
});
then just add your html to the page like this, the only point here is to store the item.Id:
$.each(data, function (i, item) {
item.Date = internationalDateTime(item.Date );
$(Mustache.to_html(template, item)).appendTo('#list-container')
.find("input[name=btnView]").attr("itemId", item.Id);
});
your problem this way is just to get access to item.Id.
You can trim it down, but for readability I normally do the exact type of thing you've posted...
$.each(data, function (i, item) {
item.Date = internationalDateTime(item.Date );
var html = Mustache.to_html(template, item);
$(html)
.appendTo('#list-container')
.find('input[name=btnView]')
.on('click', function() {
loadView(item.Id);
});
});
You could also get rid of the html variable, if you really wanted to, but I think you can go too far with minimizing code.
appendTo() will return the html as a jQuery object so you can find the input elements specified, and then attach a click event handler, all in one hit.
What's about with:
$.each(data, function (i, item) {
item.Date = internationalDateTime(item.Date);
var html = Mustache.to_html(template, item);
html.querySelector('input[name=btnView]').addEventListener('click', function() {
loadView(item.Id);
}, false);
$('#list-container').append(html);
});

jQuery mobile - how to connect between <a href> and the click event?

I'm a newbie to jQuery and jQuery mobile.
I followed a few samples and documentations and created the following code:
function initListByUrl(id, requestUrl) {
$.ajax({
url: requestUrl,
type:'GET',
dataType:'json',
success: function(data) {
var items = []
$.each(data, function(i, elem) {
items.push('<li id="cat_li_'+i+'">' + elem.name + '</li>');
});
id.html(items).listview('refresh');
}
});
}
$(document).on("click", '[id^=cat_li]', function(event, ui) {
console.log(3);
})
I need to have the elem event from the $.ajax available in the context of the click event
This is because the elem object holds a field that is relevent when the item is clicked.
How should I do it?
EDIT
just to clarify.
the initListByUrl functions is called in document-ready. It builds a list view by the retrieved json object which contains an array.
if I had elem in the context of the on-click event I would have done something like this:
$(document).on("click", '[id^=cat_li]', function(event, ui) {
call_some_function(elem.someField);
})
My issue is how do I have the appropriate elem object in the scope of the on-click event?
EDIT 2
This is my full code:
var stack = []
var site_url = 'http://localhost:3000';
$(function() {
initCategoriesList();
$("#places").on('pageinit', function() {
var category = stack.pop();
initPlacesList(category);
});
$("#place").on('pageinit', function() {
});
});
function initCategoriesList(id, requestUrl) {
$.ajax({
url: site_url + '/categories',
type:'GET',
dataType:'json',
success: function(data) {
var items = []
$.each(data, function(i, elem) {
items.push('<li id="cat_li_'+i+'">' + elem.name + '</li>');
});
$("#categories_ul").html(items).listview('refresh');
}
});
}
function initPlacesList(category_id) {
$.ajax({
url: site_url + '/business_places/category/' + category_id,
type:'GET',
dataType:'json',
success: function(data) {
var items = []
$.each(data, function(i, elem) {
items.push('<li id="place_li_'+i+'">' + elem.name + '</li>');
$("#places_ul").html(items).listview('refresh');
var element = $("#place_li_" + i)[0];
$.data(element, "object", elem);
});
$("#places_ul").html(items).listview('refresh');
}
});
}
$(document).on("click", '[id^=cat_li]', function(event, ui) {
stack.push(event.target.innerText);
})
$(document).on("click", '[id^=place_li]', function(event, ui) {
var place = $.data(this, "object");
alert(place.name);
})
var place = $.data(this, "object");
ends up having undefined
Your best bet is going to be to create custom data attributes inside the li element to be accessed at a later time. Push the data you need to these custom attributes. Example:
items.push('<li id="cat_li_'+i+'" data-custom-cool="' + elem.someData + '">' + elem.name + '</li>');
Now, you can pull out the data as you need it with this inside your click handler.
$(this).data("custom-cool"); //this is equiv to elem.someData .
Or, if you have bigger data, you can store the object with the element with $.data:
$.each(data, function(i, elem) {
items.push('<li id="cat_li_'+i+'">' + elem.name + '</li>');
});
id.html(items).listview('refresh');
var element = $("#cat_li_" + i)[0]; //cant use jQ object
$.data(element, "object", elem); //assign object
});
Now your click handler should be able to access the object like so (inside handler):
console.log($.data(this, "object").objProperty); //replace objProperty with your property to get.
Demo: http://jsfiddle.net/tymeJV/vx8Xt/1/ Click on "testdiv" and see the console.
I think the problem is with id.html(items), .html() doesn't accept an array.
id.html(items.join('')).listview('refresh');
Also to fix your other problem, you should use classes instead of ids :
function initListByUrl(id, requestUrl) {
$.getJSON(requestUrl, function(data) {
var items = []
$.each(data, function(i, elem) {
items.push('<li class="cat">' + elem.name + '</li>');
});
id.html(items).listview('refresh');
});
}
$(document).on("click", '.cat a', function(event, ui) {
console.log(3);
});
Like ajax is asynchronous by default, you have two options:
You can make the ajax request synchronous by switching the option async to false - for more details, see jQuery.ajax() API
You can save the elem in a global variable and use it in the onclick-handler
Maybe it would also be helpful if you tell us, when the function initListByURL() is executed.
You should move the event binding into the success function, after all item in the list has been attached to Document
success: function(data) {
var items = []
$.each(data, function(i, elem) {
items.push('<li id="cat_li_'+i+'">' + elem.name + '</li>');
});
id.html(items).listview('refresh');
// move your click event handling here
}

JQueryUI calling .accordion twice on one id

I'm trying to use AJAX to dynamically generate a JquerUI Accordion based on what is selected in a box. Currently I have
<div style="display:none" id="testselect">
</div>
With JS
$("#courseselect").change(function () {
$("#testselect").html(""); // Empty any previous data
$("#testselect").css("display", "block"); // Display it if it was hidden
$.getJSON('json.php?show=tests&courseid=' + $(this).val(), function(data) {
for(x in data)
{
$("#testselect").append("<h3 value=\"" + data[x].uno + "\">" + data[x].name + "</h3>");
$("#testselect").append("<div>Foo</div>");
}
$("#testselect").accordion({ change:function(event, ui) { courseid = ui.newHeader.attr("value");
} });
});
});
Now this works the first time I change my selection, but after that it reverts to plain old unformatted HTML. As if the call to .accordion() was never done. I'm guessing this has something to do with JQuery not wanting me to format something twice, but I really have no idea.
Try to destroy the accordion before you empty the div and start again:
$("#courseselect").change(function () {
$("#testselect")
.accordion("destroy")
.empty() // equivalent to .html("");
$.getJSON(...
More info here.
Good luck!

Categories