I have some code which sets the html() of a div to be the result of a Mustache call against a particular piece of JSON
function render_bugs(json_file){
$.getJSON(json_file, function(json) {
$("#bug-list").html(Mustache.to_html($('#template').html(), json));
The first time the function is called, it is fine. However when I call it with a different "json_file". It fails with the following error:
haystack is null
return haystack.indexOf(this.otag + needle) != -1;
I initially thought the problem was with the JSON file so I swapped the paramter names around but that's not it, the json is fine.
I then added a test line where I just set the html before the mustache call, like so:
function render_bugs(json_file){
$.getJSON(json_file, function(json) {
$('#bug-list').html('<p>foo</p>');
$("#bug-list").html(Mustache.to_html($('#template').html(), json));
And it doesn't work at all.
It's like Mustache doesn't want to work if the element it is being rendered to has content in it already
Is there any way around this?
Worked it out
This was the markup for the page:
<div id="bug-list" />
<div id="template">
<p><strong>{{bugs}}</strong> bugs found in mingle</p>
{{#repos}}
<h2>{{repo-name}}</h2>
<ol>
{{#hotspots}}
<li>
<p class="file-name"><a>{{score}} - {{file}}</a></p>
<ol>
<li><em><span class="line-number">{{lines}}</span> lines of code</em></li>
<li><em><span class="traits">{{traits}}</span> traits mixed in</em></li>
{{#commits}}
<li>
<strong>{{date}}</strong> - {{message}}
<div class="code">{{{change}}}</div></li>
{{/commits}}
</ol>
</li>
{{/hotspots}}
</ol>
{{/repos}}
</div>
Turns out me closing the "bug-list" div with the xml short-hand doesn't play nice. I'm guessing it assumed that I hadn't closed it properly and so the template div lived inside bug list. Therefore the first render call would overwrite the template and that would make the second call fail.
By changing the first line to
<div id="bug-list"></div>
It worked
Stupid browsers
Related
I'm working on a project where I have to delete en element in a certain condition (if). My code generates a <li> in which data is inserted via an array. I need to delete that <li> if some conditions are met.
Since removeParent() doesn't exist I've found different methods saying to use
e.parentNode.parentNode.removeChild(e.parentNode);
Rings a bell, it works in certains cases of course.
BUT
In my case, this is dynamically rendered elements in an array inside the <li> and there is no parent of the parent, so I get an error.
My script looks for an element in the <li>, in my test I use a <div> found by its class.
$(node).find('.results-name')[0].parentNode.remove();
Does NOT work unfortunately so I'm looking for other ideas...
Any clue?
Thanks a lot!
The thing is the code is huge and I can't copy/paste everything here.
Here's more info:
- in the page I have a template that's used by the javascript to populate a div with all the contents. I have ~20 results.
The template starts like this :
<script id="itemtemplate" type="geowacht/template">
<div class="results-name">
<h4 class="show-more-name itemaponaam" data-target="#result"></h4>
<div class="d-block" id="result">
<div class="itemaddress"></div>
<div class="itemgeodesc"></div>
<div class="itemphone"></div>
The pages calls a script that queries an API and returns 20 results. These results are parsed and added to the page using the template.
Here's the beginning of the code:
apiconfig.default_populateItemNode = function(node, apotheekData, wachtPeriodeData, authenticationData) {
$(node).find('.itemaponaam')[0].setAttribute('data-target', '#result-' + itemPos);
$(node).find('.buttons')[0].setAttribute('id', 'result-' + itemPos + '-buttons');
$(node).find('.buttons')[0].setAttribute('data-apbnb', apotheekData.pharmacy.id);
Here is The problem i am trying solve. I would like to create a JS script that uses angular to dynamically create div elements while adding an additional expression eg {{levelone}}.
Here is an an example of what i am expecting the output to be if i know i have 5 iterations of Dom elements.
<div ng-switch-when="0">{{levelZero}}</div>
<div ng-switch-when="1">{{levelOneA}}{{levelOneB}}</div>
<div ng-switch-when="2">{{levelTwoA}}{{levelTwoB}}{{levelTwoC}}</div>
etc.....
So as you can see i am adding an expression on each time. I just dont know how i can keep adding them on via a repeat loop and then get them to compile correctly with AngularJS. I am trying to make my DOM as Dynamic as possible.
EDIT
Every time i loop 1 more i am adding an expression ->{{expression}} to the div with JS or angular. I am not hard coding the expression into each div as each div is also dynamically created. But with a twist i am adding that extra expression ie 3 expressions from the previous div and adding one more expression making four. see example below.
<div ng-switch-when="3"{{levelTwoA}}{{levelTwoB}}{{levelTwoC}}</div>
This one below is dynamically generated
<div ng-switch-when="4"{{levelTwoA}}{{levelTwoB}}{{levelTwoC}}{{THIS EXPRESSION IS GENERATED IN js AND ADDED & COMPILED}}</div>
The DOM will be dynamic as long as your data bindings are. I need more info (data model, expectations) to be more accurate but if you set up your data and bind it correctly, it should work. for example if your data looked like this
var data = {
"levelOne" : {},
"levelTwo" : {
"elements" : ["<span id="firstEl"></span>, ...]
},
"levelThree" : {
"elements" : ["<span id="firstEl"></span>, <span id="secondEl"></span>, ...]
}
Then in your template do what #paulgoblin suggested.
}
You could ng-repeat within each switch case. Eg.
<div ng-switch-when="0">
<span>{{levelZero}}</span>
</div>
<div ng-switch-when="1">
<span ng-repeat="expression in levelOne">{{expression}}</span>
</div>
<div ng-switch-when="2">
<span ng-repeat="expression in levelTwo">{{expression}}</span>
</div>
You might want do this with scope function.
<div ng-switch="assignment.id">
<div ng-switch-when="1">{{ getExpressions(assignment.id) }}</div>
<div ng-switch-when="2">{{ getExpressions(assignment.id) }}</div>
</div>
I'm trying to make a dynamic text a link with javascript:
<div class="container">
<div class="form-current">
<form>
<h2 style="margin-left:10px" ><a href='#' onclick="homePage()" id="h2Current" ></a></h2>
<div id="node-current"></div>
</form>
</div>
This is the html and the text is loaded from a DB through a javascript function:
var h2Current = document.getElementById('h2Current');
h2Current.innerHTML = 'Day '+data[0]['day'];
the parameter "data" is a simple Json. The text appear underlined correctly but is impossibile to click.
Thanks in advance
You need to check your JSON. Check JSON i have written is a correct one. check your JSON format. You can use jsonlint.com to validate JSON you are trying to use.
<html>
<head>
</head>
<body>
<div class="container">
<div class="form-current">
<form>
<h2 style="margin-left:10px" ><a href='#' onclick="homePage()" id="h2Current" ></a></h2>
<div id="node-current"></div>
</form>
</div>
</div>
<script>
var data = [{ 'day':'monday'},{ 'day':'tuesday'}]
var h2Current = document.getElementById('h2Current');
h2Current.innerHTML = data[0]['day'];
</script>
</body>
The problem is not the JSON since you say that it appears and is underlined properly. The issue is that you are either not actually calling your 'homePage' function during the 'onclick' event, or there is an unhandled exception in the code of your 'homePage' function. Here is how you go about debugging this issue.
You need to open your site in Chrome, and open the developer tools, 'F12'. Click the 'Sources' tab, and find your .JS file, or the page file, if it contains the function, 'homePage' inline. You may need to open the 'File Navigator'. If this is the case, click the "arrow in the box" directly beneath the 'Elements' tab.
Once the file is opened, find the function declaration 'homePage' and breakpoint the first non var declarative line. Now, simply click the link and step through the function. You may find that you are not even calling the function at all and you may even see JS exceptions listed. Address any exceptions which appear inline in your code. If you are actually reaching your function, step through every line, 'F11' including any nested functions, until you find the exception.
I just started using Mustache and I like it so far, but this has me perplexed.
I am using the GitHub gist API to pull down my gists, and part of what I want to do is include the embedding functionality into my page. The problem is Mustache seems to not want to have anything to do with my dynamic script tag.
For example, this works fine:
<div class="gist-detail">
{{id}} <!-- This produces a valid Gist ID -->
</div>
Additionally, this works perfect:
<div class="gist-detail">
<script src='http://gist.github.com/1.js'></script> <!-- Produces the correct embed markup with Gist ID #1 -->
</div>
If I try to pull these together, something goes terribly wrong:
<div class="gist-detail">
<script src='http://gist.github.com/{{id}}.js'></script> <!-- Blows up! -->
</div>
Chrome Inspector shows this:
GET https://gist.github.com/%7B%7Bid%7D%7D.js 404 (Not Found)
... which looks like to me something is weird with escapes or whatnot, so I switch over to the raw syntax:
<div class="gist-detail">
<script src='http://gist.github.com/{{{id}}}.js'></script> <!-- Blows again! -->
</div>
And I get the same result in Inspector:
GET https://gist.github.com/%7B%7B%7Bid%7D%7D%7D.js 404 (Not Found)
How do I get the correct values to embed in the script tag?
EDIT
I am injecting the template as follows (in document.ready:
function LoadGists() {
var gistApi = "https://api.github.com/users/<myuser>/gists";
$.getJSON(gistApi, function (data) {
var html, template;
template = $('#mustache_gist').html();
html = Mustache.to_html(template, {gists: data}).replace(/^\s*/mg, '');
$('.gist').html(html);
});
}
The actually template is inside of a ruby partial, but it is wrapped in a div (not a script tag, is that a problem?) (that's hidden):
<div id="mustache_gist" style="display: none;">
{{#gists}}
<!-- see above -->
{{/gists}}
</div>
I assume a div is ok rather than a script because in either case, I'm pulling the .html(). Is this a bad assumption?
To avoid automatic escaping in Mustache use {{{token}}} instead of {{token}}.
It seems like your template is in HTML and trying to retrieve the template using html() results in a pre-URL-escaped template to be returned. Try placing your template inside a <script type="text/html"> tag instead.
When you embed your template inside an HTML element that excepts more HTML elements as children, it may get processed by the browser as HTML. Escaping may occur. By using a <script> tag with a non-script content type, you're basically telling the browser not to touch your template.
It looks like your script is getting requested before Mustache has a chance to update the src property. What you want to do is define the template in a way that it's not parsed as part of the DOM. A common approach is to define your template inside of a <textarea> tag. This will preserve formatting and prevent character escaping.
<textarea id="gist-detail-template" style="display:none">
<script src='http://gist.github.com/{{id}}.js'></script>
</textarea>
Now, to instantiate the template:
var template = $('#gist-detail-template').val();
var html = Mustache.to_html(template, yourTemplateData);
Here's an official example: http://mustache.github.com/#demo
I'm trying to make a cross platform mobile application using jQuery Mobile.
I have a JSON string that displays information about a specific object (check it out here: http://app.calvaryccm.com/mobile/web/teachings/json?callback=?) and I want it to turn it into a list view that connects to a single item view. The problem is, the listview isn't displaying like a list at all. It is almost like HTML without CSS. Check it out here: http://mbeta.calvaryccm.com/#teachings
This is the Javascript for parsing the JSON string:
<!-- Getting Teaching Data -->
<script type="text/javascript">
$(document).ready(function () {
$.getJSON("http://app.calvaryccm.com/mobile/web/teachings/json?callback=?",
function (data) {
//remove any characters from the query that might be unsafe to use as an ID for a page
//data.pageId = data.MessageNumber.replace(/[^\w]/, "");
//Feed the data to the template and add the new page to the body.
var res = $("#teachingTemplate").tmpl(data); //.appendTo(document.body);
$("#teachings").append(res);
//Grab a reference to that shiny new page
//var newpage = $("#" + data.pageId);
});
});
//Makes date readable
function GetDate(jsonDate) {
var value = new Date(parseInt(jsonDate.substr(6)));
return value.getMonth() + 1 + "/" + value.getDate() + "/" + value.getFullYear();
}
This is supposed to be the list view:
<script id="teachingTemplate" type="text/x-jquery-tmpl">
<div id="${MessageNumber}">
<div data-role="header">
<a data-icon="arrow-l" href="#" data-rel="back">Back</a>
<h1>${Title}</h1>
</div>
<div data-role="content">
<div class="teachingsForm">
<ul data-role="listview">
<li><a href="singleTeachingView" class="tableImage">
<img src="" alt=""/>
<h3>${Title}</h3>
<p>${Speaker} - ${GetDate(MessageDate)} - ${MessageNumber} {{if Book != null}} - ${Book.BookName} ${ChapterVerse}{{/if}}</p>
</a>
</li>
</ul>
</div>
</div>
<div data-role="footer">
<h4>2011 Calvary Chapel Melbourne</h4>
</div>
I cannot figure out why my listview isn't displaying right. If you want to see it in action look here: http://mbeta.calvaryccm.com/#teachings . I need help getting my listview to display right and direct to the right page.
It looks exactly like what your template says it should look like. Note that each of your <ul> elements only has one <li> element in it.
Your template starts off with an outer <div>, and then there's a "header" <div> with the <h1> title. Then there's the "content" <div>, and ultimately the <ul>, and finally the "footer". That's what your result page looks like. If you want to do some sort of iteration, well, you'll have to explicitly do that in your template, because otherwise the template code will assume you just want it to re-apply the template to each object in the array you pass it.
There's nothing wrong with the "JSON parsing". Note that in your JSON, there's no need to quote "/" characters with "\" and in fact (though it doesn't matter for JSONP) it's not valid JSON.
edit — OK so now that I've pulled my head out from wherever it was I think I see what you're doing. The problem may be that you just need to call
$.mobile.changePage();
at the end of your JSONP callback function. However I note that your "$.mobile" doesn't have a "changePage()" function ... I don't know what that means. You're using a pretty old version of jQuery too.