Appending elements to a DIV from a JSON array in Polymer - javascript

I'm struggling right now with inserting a set of divs into a core-header-panel inside a paper-shadow in Polymer. I am getting a set of values from a JSON array and I need to create a div with HTML content (eventually checkboxes) for each of the values. Here's the relevant snippet of code:
<paper-shadow class="card upload-options-box" z="1">
<core-header-panel flex id="graphHeaderList">
<core-toolbar class="upload-option-header">
<span flex>Variable</span>
</core-toolbar>
<core-label horizontal layout> // this is all just an example of what I eventually want to insert
<paper-checkbox for></paper-checkbox>
<div vertical layout>
<h4>MakeCircuitCreated</h4>
</div>
</core-label> // end of example of insert
</core-header-panel>
</paper-shadow>
and JQuery:
function addHeaders(){
$.getJSON('http://myURL/getDataHeaders', function(data) {
var headerArray = [];
$.each(data, function(key, val) {
$('#graphHeaderList').append("<div id='" +val +"'></div>");
console.log(val);
headerArray.push(val)
});
console.log(headerArray);
});
}
window.onload = addHeaders; //grabs the header values when the page is loaded
My JSON:
{
"headers": [
"MakeSpawnFish",
"MakeEndGame",
"MakeModeChange",
"MakeConnectComponent",
"MakeCircuitCreated",
"MakeStartGame",
"MakeSnapshot",
"MakeResetBoard",
"MakeAddComponent",
"MakeCaptureFish",
"MakeRemoveComponent",
"MakeDisconnectComponent"
]
}

It appears to me your $.each is calling the wrong thing.
In your json file you have a key called headers. When your each function iterates, it gets 1 key and adds it's members, which is an array, to the div. I tested it and got one div with every single member as it's id!
So you may need to nest a second each function to be called on the inner array
$.each(data, function(key, val) {
$.each(val, function(index,value){
$('#graphHeaderList').append("<div id=" + "'" + value + "'" + "></div>");
console.log(value);
headerArray.push(value);
}
);
https://api.jquery.com/jquery.each/

Your code:
$('#graphHeaderList').append("<div id='" +val +"'></div>");
Won't work, because jQuery can't find the element in its scope. However, polymer automatically creates id element references through its automatic node finding feature:
this.$.graphHeaderList
So it should work as expected if you use:
$(this.$.graphHeaderList).append("<div id='" +val +"'></div>");

Related

using 'this' references with meteor.template.rendered

suppose I have a Meteor template called message, where the client can post messages. the post is wrapped in a div that gets an id equal to its unique id in the Mongo collection.
<template name="message">
<div class="msg comment" id="{{this._id}}">{{msg}}</div>
</template>
is there anyway to reference the specific id in Meteor.message.rendered? right now I am using this._id and it's not working. Here is my function
Template.message.rendered = function() {
texts = $('this._id').html();
texts = texts.replace(/#(\w+)/g,
"<a href='https://www.google.com/?q=$1'target='_blank'>$&</a>");
$("this._id").html(texts);
}
Four things:
You're using a string instead of the variable: $('this._id') -> $(this._id)
The context (this) of the rendered function is a template helper, and not the data itself (which is the context of the template), so replace this._id with this.data._id to match {{ this._id }}
It's an ID selector : $(this.data._id) -> $('#' + this.data._id)
Rendered callbacks run whenever the template is rerendered, and whenever a subtemplate (a template contained within the template) is rendered, so you should flag when it has been rendered (source, interesting article about meteor rendered).
Final code :
Template.message.rendered = function() {
if(!this.rendered) {
this.rendered = true;
texts = $('#' + this.data._id).html();
texts = texts.replace(/#(\w+)/g,"<a href='https://www.google.com/?q=$1'target='_blank'>$&</a>");
$('#' + this.data._id).html(texts);
}
}

too much HTML in an ajax script?

I read from this page that appending a lot of elements is bad practice and I should build up a string during each iteration of the loop and then set the HTML of the DOM element to that string. Does the same go for using too much HTML in the loop?
I have an AJAX script that parses JSON data. It requires adding data to different existing elements, like this:
$.ajax({
url: "url",
success: function (data) {
$(data.query.results.json.json).each(function (index, item) {
var title = item.title, // A,B,C or D
age = item.age,
background = item.background,
ingredient = item.Ingredient;
$('.'+ title+'_ingredient').html(''+ingredient+'')
$('.'+ title+'_age').html(''+age+'')
$('.'+ title+'_background').html(''+background+'')
});
},
error: function () {}
});
HTML:
<div class="A_ingredient"></div>
<div class="B_ingredient"></div>
<div class="C_ingredient"></div>
<div class="D_ingredient"></div>
<div class="A_age"></div>
<div class="B_age"></div>
<div class="C_age"></div>
<div class="D_age"></div>
<div class="A_background"></div>
<div class="B_background"></div>
<div class="C_background"></div>
<div class="D_background"></div>
Is it necessary to build up a string first? If so, can you show me how to do that?
It is purely about the time it takes to process calls to html() so they simply recommend you reduce the number of calls. In this case you could build them once in a loop then sets the div html once for each.
Update:
Based on your update, aside from all the extra trailing quotes you don't need to add (a string is a string is a string), your code is fine as is. You only hit each item once.
e.g.
$.ajax({
url: "url",
success: function (data) {
$(data.query.results.json.json).each(function (index, item) {
var title = item.title, // A,B,C or D
age = item.age,
background = item.background,
ingredient = item.Ingredient;
$('.'+ title+'_ingredient').html(ingredient);
$('.'+ title+'_age').html(age);
$('.'+ title+'_background').html(background);
});
},
error: function () {}
});
Note: If your item properties (Age, Background, Ingredient) are simple values (not objects or arrays), yo do not need the leading ''+s either.
Previous
Assuming you actually want to concatenate the results (you are only keeping the last ingredient at the moment), you could do something like this:
e.g.
$.ajax({
url: "url",
success: function (data) {
var ingredients = '';
$(data.query.results.json.json).each(function (index, item) {
var title = item.title;
var ingredient = item.Ingredient;
ingredients += ingredient;
});
$('.aclass').html(ingredients);
$('.bclass').html(ingredients);
$('.cclass').html(ingredients);
$('.dclass').html(ingredients);
},
error: function () {}
});
Which can be reduced to:
$('.aclass,.bclass,.cclass,.dclass').html(ingredients);
The contents of each div are identical in your example, so you only need a single string.
In this instance you would probably need some form of delimiter between ingredients, but your example is too vague.
e.g.
ingredients += ingredient + '<br/>';
In your example, you're setting the HTML on many different document elements.
If they're grouped in some way, for example all in a Div with ID #Container, you could build a string of the HTML and set the content of the whole Div at the end of it, something like this:
$.ajax({
url: "url",
success: function (data) {
var sHTML="";
$(data.query.results.json.json).each(function (index, item) {
var title = item.title,
background = item.background,
ingredient = item.Ingredient;
// not sure what your actual HTML is (div/span/td etc) but somethign like this?
sHTML+="<div>"; // an opening container for this item
sHTML+='<div class="'+title+'_ingredient">'+ingredient+'</div>')
sHTML+='<div class="'+title+'_age">'+title+'</div>')
sHTML+='<div class="'+title+'_background">'+background+'</div>')
sHTML+="</div>";
});
$("#Container").html(sHTML);
},
error: function () {}
});
Note I haven't tested this code, but you see the principal hopefully.
That is, build a string of the HTML then set one element at the end with the content.
I have done this a lot in a recent project and haven't seen any speed issues (maybe 50 'items' to set in my case).
HTML will initially look like this :
<div id="container">
</div>
Then end up like this (2 x items in this example) :
<div id="container">
<div>
<div class="<sometitle1>_ingredient">ingredient 1</div>
<div class="<sometitle1>_age">age 1</div>
<div class="<sometitle1>_background">background 1</div>
</div>
<div>
<div class="<sometitle2>_ingredient">ingredient 2</div>
<div class="<sometitle2>_age">age 2</div>
<div class="<sometitle2>_background">background 2</div>
</div>
</div>
subsequent calls will replace the element's content with new values, replacing the old items.
Building a string is, I would imagine, less processor-heavy than setting the html() on lots of elements individually. Each time you use html() I'm guessing that the browser has to go some way towards working out any knock-on effects like expanding the width of an element to accomodate it or whether events will still work as they did, etc - even if actual rendering is only run at the end of the process. This way you use html() once, although what you're setting is more complex.
Hope this helps.

How to dynamically construct html tag attriburtes with json data?

I am having (Strigified) json data in a variable called test. I am constructing html elements dynamically and also I want json data to be inserted in an element attribute.
var templateHtml = "":
$.each(loopValues, function(Key, Value) { // Loops which constructs dynamic data
var test = '{"type": "page"}'; // this is the json data which need to be appended as data-all attribute value.
templateHtml = templateHtml.concat("<a data-all="+ test +" href='javascript:;' class='icon' id='TestTt'></a>");
}
$("#sortable1").html(templateHtml);
After executing these lines, when I see the constructed element, It is totally scrambled. How to get a well formatted json data in a element attribute ?
I do not want to append json data on attribute using jquery after constructing html. I want this functionality at html construction time.
I refered
http://gabrieleromanato.name/jquery-binding-animation-data-to-elements-with-json/
http://api.jquery.com/jQuery.parseJSON/
Any Idea ?
First, your code miss some syntax element :
var templateHtml = ""; // use ; not :
$.each(loopValues, function (Key, Value) { // Loops which constructs dynamic data
var test = '"{type": "page"}'; // this is the json data which need to be appended as data-all attribute value.
templateHtml = templateHtml.concat("<a data-all=" + test + " href='javascript:;' class='icon' id='TestTt'></a>");
}); //close the loop call
Then you need to add single quotes around your test variable when you append it. I suggest you choose where to use single quotes or doubles and stick to the choice permanently. I personnally use double quotes in HTML and single quotes in JS :
var templateHtml = '';
$.each(loopValues, function (Key, Value) { // Loops which constructs dynamic data
var test = "{type: 'page'}"; // this is the json data which need to be appended as data-all attribute value.
//since its JSON i use single quote inside but double outside.
templateHtml = templateHtml.concat('<a data-all="' + test + '" href="javascript:;" class="icon" id="TestTt"></a>');
});
FIDDLE here
What you need is creating elements with jQuery with json as parameters.
For example creating a simple table
var $table = new $('<table>', { 'cellpadding' : '5', 'cellspacing' : '4' });
var $tr = new $('<tr>');
var $td = new $('<td>', { 'class' : 'test' });
$td.text('cell contents');
$tr.append($td);
$table.append($tr);
$('body').append($table);
You can keep your json in DOM without data- attribute, just use:
$("#sortable1").html("<a href='javascript:;' class='icon' id='TestTt'></a>");
$( "#sortable1 > a" ).data( 'all', test );
According to jQuery .data() API. Data value can be any JavaScript type.
To get this JSON you will need just to write:
console.log( $( "#sortable1 > a" ).data( 'all' ) );
UPDATE:
But better is to add data at creation proccess:
$.each(loopValues, function(Key, Value) { // Loops which constructs dynamic data
$( "#sortable1" ).append( $( "<a/>" ).addClass( "icon" ).data( "all", {"type": "page"} ).attr( "id", "TestTt" ) );
});

Why is my code looping twice?

I'm making a data visualisation tool where you can input your own data. The data values are stored in an unordered list like this: <ul><li data-name='name'><a href='#' onclick='showEditDv(this);'>Edit</a><span class='name'>name</span><span class='seperator'> | </span><span class='value'>7</span></li></ul. There can be more than one list item in the list. When you click on the Edit button it calls the showEditDv() function, giving a reference to itself. Before I show the function, I will say that the data object is organised like this:
data ->
name: "root",
children: [ {name: "something", size: "7"},
{name: "something-else", size: "999"} ]
This is the code for the function:
function showEditDv(object) {
var name = $(object).parent().attr("data-name"),
input = new Opentip($(object), {removeElementsOnHide: true, target: null, showOn: null, hideTrigger: "closeButton"}),
disabled = (data.children[getChildIndexByName(name)].hasOwnProperty("children")) ? "disabled" : "";
input.setContent("<label>Name:</label><input type='text' data-prevname='" + name + "' value='" + name + "' class='dv-add-name' /><label>Value:</label><input " + disabled + " type='text' class='dv-add-value' value='" + data.children[getChildIndexByName(name)].size + "' /><button class='callEditDv'>Apply</button>"); // Set content of opentip
input.show();
$("body").on("click", ".callEditDv", function() {
var newname = $(this).siblings(".dv-add-name").val(),
prevname = $(this).siblings(".dv-add-name").attr("data-prevname"),
value = $(this).siblings(".dv-add-value").val();
if (newname !== prevname)
{
data.children[ getChildIndexByName(prevname) ].name = newname; // Update name
$(object).parent().attr("data-name", newname); // Update parent data
$(object).siblings(".name").text(newname); // Update form
}
if (data.children[ getChildIndexByName(newname) ].size !== value)
{
data.children[ getChildIndexByName(newname) ].size = value;
$(object).siblings(".value").text(value);
}
input.hide();
});
}
It uses Opentip, which is just a way of creating dynamic popups / tooltips. The problem is that once you have changed a data value once, when you try to change it again it loops through the code twice! The first time everything works as expected, but the second time it does it again, using the same prevname, which means that getChildIndexByName returns undefined and it can't set the variable causing an error. getChildIndexByName loops through the values of data.children checking the names until it finds a match, and then returns the index of the object in the array.
Thanks in advance!
Try this:
$("body").off('click').on("click",...
jQuery Documentations
Event handlers attached with .bind() can be removed with .unbind().
(As of jQuery 1.7, the .on() and .off() methods are preferred to
attach and remove event handlers on elements.)
change:
$("body").on("click",...
to
$("body").unbind('click').on("click",
Hope this help!

Javascript each loop over JSON only getting first element?

I'm using Jquery mobile, so ignore some of the following overdone css, its not related to the core issue.
I'm having a problem looping over the "Places" in my JSON packet/javascript object. I am getting a response with multiple "Places", but can't seem to figure out how to iterate over them. My 'i' variable in my each loop is working correctly for the first element, and displaying its corresponding name & image.
Here's my server side Django view (pretty straight-forward if your unfamiliar with Python):
def tonight_mobile(request):
callback = request.GET.get('callback', '')
def with_rank(rank, place):
return (rank > 0)
place_data = dict(
Places = [make_mobile_place_dict(request, p) for p in Place.objects.all()]
)
xml_bytes = json.dumps(place_data)
return HttpResponse(xml_bytes, content_type='application/json; charset=utf-8')
My server is acknowledging the request and returning the following:
"GET /api/0.1/tonight-mobile.json&callback=jsonp1293142434434 HTTP/1.1" 200 167
Here's my response:
callback({"Places": [{"url": "http://localhost:8000/api/0.1/places/3.plist",
"image_url": "http://localhost:8000/static/place_logos/Bengals_1.png",
"name": "Bob's Place", "events": 2},
{"url": "http://localhost:8000/api/0.1/places/2.plist",
"image_url": "http://localhost:8000/static/place_logos/Makonde_Mask.gif",
"name": "My Bar", "events": 0},
{"url": "http://localhost:8000/api/0.1/places/1.plist",
"image_url": "http://localhost:8000/static/place_logos/Quintons_1.png",
"name": "Quinton's", "events": 1}]})
------------
My getJSON and callback method have evolved into this:
<script>
function loadJSON(){
$.getJSON("http://localhost:8000/api/0.1/tonight-mobile.json&callback=?", callback(data));
}
function callback(data){
$("#tonight-list").each(data.Places, function(i) {
$(this).append("<li role='option' tabindex='" + data.Places[i] + "' class='ui-li-has-thumb ui-li ui-btn ui-btn-icon-right ui-corner-top ui-corner-bottom ui-controlgroup-last ui-btn-down-c ui-btn-up-c' data-theme='c'><div class='ui-btn-inner ui-corner-top ui-corner-bottom ui-controlgroup-last'><span class='ui-icon ui-icon-arrow-r'></span><div class='ui-btn-text'><img src=" + data.Places[i].image_url + " alt=" + data.Places[i].name + " class='ui-li-thumb ui-corner-tl ui-corner-bl'/><h1 class='list-title ui-li-heading' id='list-title'><a href='detail.html?id=slide' data-transition='slide' class='ui-link-inherit'>" + data.Places[i].name + "</a></h1><span class='ui-li-count ui-btn-up-c ui-btn-corner-all'>" + data.Places[i].events + " events</span></div></div></li>");
});
}
</script>
Am I confusing how the each function iterates over the JSON (which become) Javascript objects? I am pretty sure the each is my issue here, as I am only getting the FIRST element of the "Places" list. Can someone please help me out as to how to structure the looping?
each() doesn't work that way. It takes a set of elements on the page, and loops over them, calling a function for each one. In this case, you are looping over $("#tonight-list"), which will only have one item in it (IDs are supposed to uniquely identify one element in a document).
What you seem to want to do is to loop over the data (not the #tonight-list element), and add the data to that element, right? In that case, you want normal JavaScript to do the loop, something like this:
var list = $("#tonight-list");
for (var i=0, place; place=data.Places[i]; ++i) {
list.append("<li role='option' tabindex='" + i + "'>" + place.name + "</li> ...etc);
}
Note that I have no idea if you are loading trusted data that is meant to contain HTML, untrusted plain text, etc. You may need to encode the data before inserting it or (better) insert it structurally instead of concatenating strings, depending on your use-case.
You are using getJSON and each the wrong way:
function loadJSON(){
$.getJSON("http://localhost:8000/api/0.1/tonight-mobile.json&callback=?", callback);
}
function callback(data){
var target = $("#tonight-list");
$.each(data.Places, function(i) {
target.append("...");
});
}
You have to pass a reference of the callback function do getJSON, not call the function.
If you do $("#tonight-list").each() then you are iterating over the elements selected by the selector. This function takes only one argument (the callback) anyway. See the documentation.
You want $.each() which takes an array as first and a callback as second argument.

Categories