JQuery weird syntax - json

I'm new to JQuery and trying to use it to dynamically build HTML based on results of a query for JSON objects. Anyways on the JQuery API site (http://api.jquery.com/jQuery.getJSON/) I found this example where I don't understand the syntax and I can't seem to find any explanation of why this syntax is legal or how to use it.
$.getJSON('ajax/test.json', function(data) {
var items = [];
$.each(data, function(key, val) {
items.push('<li id="' + key + '">' + val + '</li>');
});
// *** THIS IS THE PART THAT IS WEIRD ***
$('<ul/>', {
'class': 'my-new-list',
html: items.join('')
}).appendTo('body');
});
Can someone refer me to documentation that explains the syntax with the comment above it?

$('<ul/>')
Creates a new UL element not attached to the DOM
$('<ul/>', {'class':'my-new-list'})
Sets DOM variables for that element using a key value pair. So now you have a UL element with a class of my-new-list.
$('<ul/>', {'class':'my-new-list', 'html': items.join('')})
This is taking the array of LI elements created above joining the elements together in a string (with no delimiter in this case, .join('-') would have put a hyphen between each LI element) and assigning to the inner html of the UL.
$('<ul/>', {'class':'my-new-list', 'html': items.join('')}).appendTo('body');
Last but not least, it appends the newly created UL element with this child LI elements to the BODY element making it visible on the page.

$('<ul/>', {
'class': 'my-new-list',
html: items.join('')
}).appendTo('body');
This simply creates a new UL element with a class of 'my-new-list' and the contents of items. It will create a structure like:
<ul class='my-new-list'>
<li id="key1">val1</li><li id="key2">val2</li><li id="key3">val3</li>
</ul>
This is simply short hand for:
$('<ul></ul>').attr('class', 'my-new-list').attr('html', items.join('')).appendTo('body');
Documentation: http://api.jquery.com/jQuery/#jQuery2

Check out the documentation for jQuery ($). Specifically, look at the part dealing with the overload jQuery( html, props ):
html: A string defining a single, standalone, HTML element (e.g. or ).
props: An map of attributes, events, and methods to call on the newly-created element.
Further down there is more information:
As of jQuery 1.4, the second argument to jQuery() can accept a map
consisting of a superset of the properties that can be passed to the
.attr() method. Furthermore, any event type can be passed in, and the
following jQuery methods can be called: val, css, html, text, data,
width, height, or offset. The name "class" must be quoted in the map
since it is a JavaScript reserved word, and "className" cannot be used
since it is not the correct attribute name.

See the jQuery documentation here. Specifically the section entitled:
Creating New Elements
This section contains details on the use of the jQuery( html, props ) overload, added in version 1.4. This is the overload used in your example. It takes an html string argument which is used to create a new DOM element and then adds the attributes contained in the props object argument.

That means you're appending a <ul> element with the my-new-list class to the body. The <li> items you've constructed in the items array are then added to the <ul>, so you'll end up with something like:
<ul class="my-new-list">
<li id="key1">val1</li><li id="key2">val2</li>...
</ul>

$('<ul/>', {
'class': 'my-new-list',
html: items.join('')
}).appendTo('body');
In jQuery, besides searching for DOM elements, you can also create them.
$('<ul/>') // or $('<ul></ul>')
This makes a new <ul> elements and returns it as a jQuery object.
The object passed as the 2nd parameter sets its attributes. Thus making this:
<ul class="my-new-list"><li id="one">O Hai</li></ul>
This <ul> is then appended to the body.

The part you don't understand is a completely different usage of the $ function.
In most cases you use $ function as a selector which returns a set of jquery elements (dom nodes wrapped as jquery objects) which you can perform some kind of operation on.
In this case you are instead using the $ function to build DOM nodes (actually, jquery objects) and then those objects you can perform functions on, such as appendTo in the example shown.
It is pretty much equavalent to writing something like
var node = document.createElement("ul");
node.setAttribute("class", "my-new-list");
node.innerHTML = items.join('');
document.body.appendChild(node);

Related

Polymer 1.x: How to print all the properties of a Polymer element?

How do I print to the console all the properties of an element I have imported into a custom element.
For example, I have a custom element my-el and in that element, I have imported a firebase-document element. I want to know the current state of the model for the firebase-document element by observing the value of all the properties of the firebase-document at a particular point in time.
my-el.html
<firebase-document id="document"
app-name="my-app"
data="{{data}}">
</firebase-document>
...
foo: function() {
...
var doc = this.$.document;
// Neither of the following "works" (see below for definition)
console.log('doc', doc);
console.log('doc.properties', doc.properties);
}
By works, I mean it does not produce the desired behavior of printing an object to the console. The object being all the properties of the doc object.
You can use console.dir(), but you can also use the %o substitution string in a standard console.log() call:
console.log( 'doc=%o', doc );
The list of substition strings is avaiable on MDN's website.
Summary from comments:
Use
console.dir( doc );

In what contexts is interpolation legal in Angular, and why?

I know that Angular's string interpolation normally operates on expressions inside Handlebars-style {{ double curly braces }}, and by observation I know that I can use it in contexts like
text outside HTML tags: <span>{{ 'string literal expression ' }}</span>
attribute values inside HTML tags: link
and not to generate attributes themselves, i.e.
<a {{ 'href="/link/to/elsewhere"' }}>link</a>
does not get interpolated.
What I'm curious about is why: what are the rules on where interpolation does and doesn't happen, where this is documented, and what the design considerations or constraints are that led to this.
I guess this is because the document is parsed as HTML by the browser before Angular sees it, so the structure is dictated by HTML and the {{ stuff }} has to appear in places that are well-formed according to HTML even before interpolation happens. But I'd appreciate knowing the whole story.
What are the rules on where interpolation does and doesn't happen ?
Angular.js uses $compile service to compile a piece of DOM. The docs says:
The compilation is a process of walking the DOM tree and matching DOM elements to directives.
In the source code of compile.js there is a function collectDirectives, I trimmed it to show only the relevant code:
function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
var nodeType = node.nodeType;
// ....
switch(nodeType) {
case 1: /* Element */
// ....
// iterate over the attributes
for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
// ....
addAttrInterpolateDirective(node, directives, value, nName);
// ....
}
// ....
break;
case 3: /* Text Node */
addTextInterpolateDirective(directives, node.nodeValue);
break;
case 8: /* Comment */
// ....
break;
}
directives.sort(byPriority);
return directives;
}
As you can see, $compile search for interpolated content only inside attributes and text nodes when it iterates a piece of DOM.
Those functions, addTextInterpolateDirective and addAttrInterpolateDirective "translate" the interpolated expression into directives that $watch interpolated expressions and update the DOM element.
Where this is documented?
The compilation phase is documented here: http://docs.angularjs.org/guide/compiler
It's getting better every day but still some in-depth stuff are not clear until you read the source code itself. I guess some things are just too compilcated to explain without showing the code.
What the design considerations or constraints are that led to this?
I guess there are two reasons:
Angular operates on DOM nodes rather than strings, If angular needed to interpolate attributes or elements then It should operate on html strings which is probably bad for performance.
There is no major use case for such things.
If you still want to interpolate everything, do that kind of magic inside a directive:
An example:
app.directive('myAnchor',function(){
return {
restrict: "E",
transclude: true,
link: function(scope,element,attrs,ctrl,$transclude) {
attrs.$observe('interpolate', function(val){
var e = angular.element("<a " + val + "></a>");
$transclude(scope,function(clone){
e.append(clone);
});
element.replaceWith(e);
});
}
};
});
Be sure to read this:
What is the difference between the $parse, $interpolate and $compile services?

Forced to use template?

This code from Dart worries me:
bool get isTemplate => tagName == 'TEMPLATE' || _isAttributeTemplate;
void _ensureTemplate() {
if (!isTemplate) {
throw new UnsupportedError('$this is not a template.');
}
...
Does this mean that the only way I can modify my document is to make it html5?
What if I want to modify an html4 document and set innerHtml in a div, how do I achieve this?
I am assuming you are asking about the code in dart:html Element?
The method you are referring to is only called by the library itself, and only in methods where isTemplate has to be true, for example this one. If you follow this link, you can also read what other fields/methods work like this.
innerHtml is a field in every subclass of Element which supports it, for example DivElement
Example:
DivElement myDiv1 = new DivElement();
myDiv1.innerHtml = "<p>I am a DIV!</p>";
query("#some_div_id").innerHtml = "<p>Hey, me too!</p>";

JQuery selectors - using html snippets as "context" in filter and find

A quick question about using context with Jquery selectors:
I'm trying to grab the text from a div element that has id="time". Can a HTML snippet be used as context in the following:
// An AJAX request here returns a HTML snippet "response":
var myTime = $("#time", response).text();
The reason I'm doing this is that I want the time variable from within the html held in response, but don't want the overhead of loading all of the html into the DOM first. (it's a large amount of html).
From the comments what I understand is the response is <span id="time">blah blah</span> which means the element time is the root variable itself, that is why the child lookup is not working.
var response = '<span id="time">blah blah</span>';
var myTime = $(response).text(); // Or $(response).filter("#time").text();
alert(myTime)
Demo: Fiddle
This method uses filter() rather than find(), the difference being:
filter() – search through the passed element set
find() – search through all the child elements only.
Did you try it?
$("#time", "<div><span id=time></span></div>")[0].id //returns 'time'
From the jQuery source code:
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor( context ).find( selector );
}
so valid selectors should work in the context parameter. Personally, I prefer using find to begin with because it keeps all the selectors in the same order instead of $("second > third", "first");

jqPlot charts on page load

I have a form where I select the number of items. Upon clicking submit, it should take me to a new page where it would display the item selected and depending on the number of items selected, it would create those many jqPlots, one for each item.
Any suggestions on how do I go about doing this?
Thanks,
S.
It's hard to give any specifics without more detail about the items, but basically you would pass a JSON structure to your view with the items to be plotted. Then you would loop through the JSON structure, creating DIV tag for each item to be plotted and appending the DIV tags to the body.
The Javascript part would look something like this:
$.each(items, function(index, value) {
$myPlot = $("<div>");
$myPlot.attr("id", "item"+index);
$.jqplot($myPlot.attr("id"), ...);
$("body").append($myPlot);
});
This question is very general, but answering (specifically and only) the question of loading multiple charts:
You need a unique HTML div id for each chart; consider using an RFC 4122 UUID (generate as needed) for each chart/div rather than a sequential index for each. Use something that looks like this as a placeholder div for each:
<div class="chartdiv" id="chartdiv-${UID}">
<a rel="api" type="application/json" href="${JSON_URL}" style="display:none">Data</a>
</div>
This embeds the JSON URL for each div inside it, in a hidden hyperlink that can be discovered by JavaScript iterating over your multi-chart HTML page.
The matter of the UUID is inconsequential -- it just seems the most robust way to guarantee a unique HTML id addressable by JavaScript for each chart.
Subsequently, you should have JavaScript that looks something like:
jq('document').ready(function(){
jq('.chartdiv').each(function(index) {
var div = jq(this);
var json_url = jq('a[type="application/json"]', div).attr('href');
var divid = div.attr('id');
jq.ajax({
url: json_url,
success: function(responseText) { /*callback*/
// TODO: responseText is JSON, use it, normalize it, whatever!
var chartdata = responseText;
jq.jqplot(divid, chartdata.seriesdata, chartdata.options);
}
});
});
});