making a list in jquery mobile using innerhtml - javascript

I am trying to create a list using the styles provided by jquery mobile. When I make the list in the html file, the list incorporates the styles that jquery mobile provide: http://jquerymobile.com/demos/1.0/docs/lists/lists-search.html
However in my website, i need to generate the list based on the number of objects in my array so I want to do this by making the html script using javascript and changing the innerHTML of a div. When I do this, a normal list appears without the stylings of jquery mobile.
Does anyone have a solution to my problem?
Here's my markup code:
function GenerateList(appArray) {
var searchList = document.getElementById('searchList');
var app;
var htmlString = "<ul data-role='listview' data-filter='true' data-filter- placeholder='Search...' data-filter-theme='a' data-theme='a'>";
for(i=0; i<appArray.length;i++) {
app = appArray[i];
htmlString = htmlString + "<li><a id=App" + (i+1).toString() + " onclick='AppSelected(id);'>";
htmlString = htmlString + "<img src='DummyImages/" + app[1] + "' alt='Logo' class='ListAppLogo'>";
htmlString = htmlString + "<h3>"+ app[2] + "</h3>";
htmlString = htmlString + "<p>" + app[4] + ".0/5.0</p>";
htmlString = htmlString + "<input type='hidden'>" + app[0] + "</a></li>";
}
htmlString = htmlString + "</ul>";
searchList.innerHTML = htmlString;
}

You'll want to make sure JQuery Mobile initializes the list after you've created it with javascript. Use the following snippet where thislist is the id of the unordered list element.
$('#thislist').listview()
Also, if the unordered list with data-role='listview' already exists, then you'll want to use the same initializer with a parameter, 'refresh'. Here is another snippet where thislist is the id of the unordered list. You'll want to use the refresh if you've added/removed items from it dynamically.
$('#thislist').listview('refresh');

I'm not taking credit for the solution instead trying to explain it in detail since it took me some time to figure it out but the changes should be something like this.
Original code:
function GenerateList(appArray) {
var searchList = document.getElementById('searchList');
var app;
var htmlString = "<ul data-role='listview' data-filter='true' data-filter- placeholder='Search...' data-filter-theme='a' data-theme='a'>";
...
searchList.innerHTML = htmlString;
}
Fixed code:
function GenerateList(appArray) {
var searchList = document.getElementById('searchList');
var app;
var htmlString = "<ul id='thislist' data-role='listview' data-filter='true' data-filter- placeholder='Search...' data-filter-theme='a' data-theme='a'>";
...
searchList.innerHTML = htmlString;
$('#thislist').listview();
}
This way it shows your list using the listview from jquery mobile.

You're not using the same CSS as jQuery Mobile. If you look at the HTML on the link you provided, you'll see that they have additional classes on their list items:
<ul data-role="listview" data-filter="true" class="ui-listview">
<li data-theme="c" class="ui-btn ui-btn-icon-right ui-li-has-arrow ui-li ui-btn-up-c">
<div class="ui-btn-inner ui-li" aria-hidden="true">
<div class="ui-btn-text">Acura</div>
<span class="ui-icon ui-icon-arrow-r ui-icon-shadow"></span>
</div>
</li>
</ul>

Related

list.js not working on dynamically created elements created dynamically using $.getJSON

I am trying to make a sortable list using list.js on codepen. The following is the code I have so far:
HTML:
<h1>FCC News Viewer</h1>
<div id="users">
<form id="searchbox">
<input type="form" class="search" id="magnifying_glass"></input>
</form>
<div id="sort-by">
<button class="sort" data-sort="date">Sort by date</button>
<button class="sort" data-sort="rank">Sort by rank</button>
<button class="sort" data-sort="author">Sort by author</button>
</div>
<ul class="list">
</ul>
</div>
Javascript:
$('document').ready(function(){
$.getJSON("http://www.freecodecamp.com/news/hot", function(json) {
for (i=0; i<Object.keys(json).length; i++) {
$('ul').append("<li class='article'><img src="+json[i].author.picture+"\><a href="+json[i].link+" class='headline'>"+json[i].headline+"</a><br><a href='http://www.freecodecamp.com/"+json[i].author.username+" class='author'>"+json[i].author.username+"</a><p class='rank_text'>"+"♥"+"<span='rank'>"+json[i].rank+"</span></p><p class='date'></p></li>")
if (i == Object.keys(json).length-1) {
var options = {
valueNames: [ 'date', 'rank', 'author' ]
};
var userList = new List('users', options);
}
}
})
})
I have both the jquery and list.js libraries loaded. When I press any of the sort buttons, three elements of the 100 I created move and not even according to the sorting category. Is there something more to creating a sortable list that I am missing?
I noticed an issue with the opening and closing quotes (double and single), also date should be included in the options, and even though I did not find it explicitly written in the documentation, it seems that the sorting class should be attached to an immediate child of the li item - this is what fixed rank sorting for me. This is how I have adjusted your codepen js:
$('document').ready(function(){
$.getJSON("http://www.freecodecamp.com/news/hot", function(json) {
for (i=0; i<Object.keys(json).length; i++) {
$('ul').append(
"<li class='article'>" +
"<img src='" + json[i].author.picture + "' /'>" +
"<a href='" + json[i].link + "' class='headline'>" +
json[i].headline +
"</a><br>" +
"<a href='http://www.freecodecamp.com/" + json[i].author.username +
"' class='author'>" + json[i].author.username + "</a>" +
"<p class='rank'>♥<span='rank-span'>"
+ json[i].rank + "</span></p><p></p></li>");
if (i == Object.keys(json).length-1) {
var options = {
valueNames: [ 'rank', 'author' ]
};
var userList = new List('users', options);
}
}
})
})
I would strongly suggest not mixing in any HTML code in the Javascript file. What you have is considered obtrusive. I would redefine the problem after you have factored out the HTML that is embedded in the Javascript, this can lead to some very messy and hard to understand code. The separation of presentation and behavior is very important.
Please see:
https://en.wikipedia.org/wiki/Unobtrusive_JavaScript
Here is the section of code concerning this:
$('ul').append(
"<li class='article'><img src="+json[i].author.picture+"\>
<a href="+json[i].link+" class='headline'>"+json[i].headline+"</a>
<br><a href='http://www.freecodecamp.com/"+json[i].author.username+" class='author'>"+json[i].author.username+"</a>
<p class='rank_text'>"+"♥"+"<span='rank'>"+json[i].rank+"</span></p><p class='date'></p></li>")

slideToggle() doesn't push elements created with jquery append() down

I do have a problem using slideToggle(). The following DOM elements won't be pushed down, they just overlap. I tried a lot of versions. I do create the tags with jquery getting a JSON from which I fill in the tag content, so I iterate over the JSON to create the HTML tags for each element :
var project_infos = '';
jQuery(document).ready(function(){
$.getJSON('project.json', function(data){
project_infos += '<div class=\"row\">'
+ '<div class=\"span3\">'
+ '<div class=\"well\">'
+ '<div>'
+'<ul class=\"nav nav-list sidebar-list\">';
for( var i = 0; i < data.length; i ++ ) {
var project_name = data[i]["item"];
project_infos += '<li>'
+'<label class=\"tree-toggler nav-header\">'
+'<i class=\"fa fa-arrow-right\"></i>' + project_name + '</label>'
+'<ul class=\"nav nav-list tree\">'
+'<li><label class=\"tree-toggler nav-header\">Katalogue</label></li>'
+'<li>'
+'<ul class=\"nav nav-list tree\">'
+'<li>Link</li>'
+'<li>Link</li>'
+'<li>Link</li>'
+'</ul>'
+'</li>'
+'<li><label class=\"tree-toggler nav-header\">History</label></li>'
+'<li><label class=\"tree-toggler nav-header\">Whole project</label></li>'
+'</ul>'
+'</li>';
}
project_infos += '</ul></div></div></div></div>';
$('#tree').append(project_infos);
$('.tree-toggler').click(function () {
$(this).parent().children('ul.tree').slideToggle('slow');
});
});
});
EDIT : screenshot of html output.
screenshot html output
Thanks in advance!
Use
find() instead of children()
$(this).parent().find('ul.tree').slideToggle('slow');
children() will only search for first level child elements.
I just reset all css styles for my div and finally it worked. I already defined styles for the sidebar and for the ul and li tags. One of the styles was the problem. It kept the elements from toggle down in the sidebar.
Thanks for your time!

jqueryui Add sortable component dynamically

Hi i'm having a problem creating a dynamically sortable list, the idea is have a button to create a list, the list has some option like add new item to itself or drag them between lists, i have a main list like that:
TL;DR:
Create and initialize a new sortable list from a ul just insertered in the DOM
<ul class="list-1">
<li id="dynamic-id" class="first-level-items">
- Some content -
</li>
<ul>
Everything works fine there, there is an action to add more ".first-level-item" and works fine, but inside those elements is and action to create another another list and inside the list other list items, so the structure should be something like:
<ul class="list-1">
<li id="dynamic-id" class="first-level-items">
<ul class="dynamic-list" id="dynamic-list-id">
<li class="dynamic-generate-li">
- content -
</li>
</ul>
</li>
<ul>
My constructor functions:
createNewCategoryRow: function(parent,obj){
var controller =this;
var insertAfter = $('[data-parent-ul="'+parent+'"]');
var element = "<li data-id='"+obj.uniqueId+"' id='"+obj.uniqueId+"' ><div class='row sub-title-inner' data-obj='"+obj.uniqueId+"'>" +
"<div class='cell cell-2 row-title '>"+
"<span class='span-title'><i> "+obj.value+" </i></span>"+
"</div>"+
"</div>";
element += "<ul class='sort sort-"+obj.uniqueId+"' data-parent='"+obj.uniqueId+"'></ul>"+
"<div class='row bold title-total-child-inner'>"+
"<div class='cell cell-2 '>"+
"<span class='span-title'><strong> "+ obj.total.value+" </strong></span>"+
"</div>";
for(var i = 0; i < obj.total.amounts.length; i++){
element += "<div class='cell overflow-cell' id='"+ obj.total.amounts[i].uniqueId +"'>"+ obj.total.amounts[i].value +"</div>";
}
element += "</div></li>";
insertAfter.append( element);
insertAfter.sortable('refresh')
//Here Everything works as expected
//Here nope
//Initialize the new generate ul container Not working :(
$('.sort-'+obj.uniqueId).sortable({
placeholder: "ui-state-highlight",
cancel: ".cancel-sort",
axis: 'y',
update: function(e, ui) {
$("ul.sort li").find('div.row').removeClass("gray");
$('.sort-'+obj.uniqueId+" li:even").find('div.row').addClass("gray");
},
stop: function(e, ui) {
var cctManager = Client.CCTManager.create();
var idArr = $.map($(this).children('li'), function(el) {
return el.id ;
})
var me = ui.item.data('id');
var position = idArr.indexOf(me);
cctManager.dragCriteriaGroup(_workpage, me, position, function(newWorkpage){
controller.set('saved_workpage',newWorkpage);
})
}
}).disableSelection();
}
//create the item lists for the new list container (ul)
createNewCriteriaRow:function(id,obj){
var insertAfter = $('[data-parent="'+id+'"]');
var element = "<li data-obj='"+obj.uniqueId+"' id='"+obj.uniqueId+"'>"+
"<div class='row'>"+
"<div class='cell cell-2 row-title'>"+
"<span class='span-title'>"+obj.value+"</span>"+
"</div>";
for(var i = 0; i < obj.amounts.length; i++){
element += "<div class='cell overflow-cell' data-obj='"+ obj.amounts[i].uniqueId +"'>"+ obj.amounts[i].value +"</div>";
}
element += "</div></li>"
insertAfter.append(element);
//Until here everything works as expected
//Here i'm trying to refresh the last created item and add some style to the childs, it add the childs but not refresh the sortable
console.log(id)
$('.sort-'+id + 'location').find('div.row').removeClass("gray");
$('.sort-'+id + 'li:even').find('div.row').addClass("gray");
$('.sort-'+id).sortable( "refresh" );
}
Both elements works on click.
Thanks

Displaying a Jquery image list

I'm having a problem with the JQuery imagelist. When opening the page for the first time, the list displays correct, the image is shown, title is shown...
Pressing the back button and re-opening the page gives a normal list, no longer the jquery listview?
I'm using a DIV element in my page like this:
<div id="dataDiv">
<ul data-role='listview' id='listing' data-theme='c'>
</ul>
</div>
This gets filled with information retrieved from an api call:
function listApiInfo() {
clearDataDiv();
var parsed = makeApiCallGet("http://someSite/SomeApi");
i = 0;
for (i; i < 15; i++) {
$("#listing").append("<li>"
+ "<img src='" + imageUrl + "' alt='img' class='ui-li-thumb' />"
+ "<h1>" + parsed[i].info + "</h1>"
+ '</a></li>'
);
}
}
on loading the div, i make sure it's an empty list item:
function clearDataDiv() {
$("#dataDiv").html(
"<ul id='listing' data-role='listview' data-theme='c'></ul>");
}
Edit: As suggested by Wibble in the comments, i did look at the cache as the problem.
Giving the div the following option solved the problem:
<div id="dataDiv" onblur='window.location.reload()'>
<ul data-role='listview' id='listing' data-theme='c'>
</ul>
</div>
I'm still not sure if this is the most elegant solution though, it gives a blank screen for a split second.

Adding html while iterating over jquery object

Is there a better way of inserting somewhat complex html into a page other than the way I'm doing now? :
function display(friends) {
$(".row").empty();
$.each(friends, function(index, friend) {
var html = '<div class="profileImage" style="float:left;padding:20px; width:200px">';
html += '<a href="/app/click/' + friend.id + '">';
html += '<img id="' + friend.id + ' " src="https://graph.facebook.com/' + friend.id + '/picture?width=200&height=200 " />';
html += '</a>';
html += '</div>';
$(".row").append(html);
});
Currently I have a list of facebook friends which are styled nicely. When a user searches through the friends, the entire content block is emptied and the result is appended (i'm using autocomplete). However the design could change and get more complex so i'm looking for a scalable way of doing what I have above.
Instead of creating the html inside the javascript, is there a smarter way of doing this? Perhaps with $.load() and passing each friend as an argument? But that seems very slow and server intensive if you have to list 100 friends.
One good way to go would be to use a templating engine, handlebars (as mentioned in the prev answer) is one of them. You could create your own as well if your scenario is simple as this. And another key thing is not to use append inside the loop, instead construct them to a temp array and add it to the DOM in the end. If your list is big and appending to the dom in the array can be expensive.
Add the template html with a placeholder for friendId
<script type="text/html" id="template">
<div class = "profileImage" style = "float:left;padding:20px; width:200px">
<a href = "/app/click/{{friendId}}">
<img id = "{{friendId}}" src = "https://graph.facebook.com/{{friendId}}/picture?width=200&height=200 " />
</a>
</div>
</script>
And
var $template = $('#template'),
$row = $('.row');
function display(friends) {
var rows = [];
$.each(friends, function (index, friend) {
var templateHtml = $template.text().replace(/{{friendId}}/g, friend.id);
rows.push(templateHtml);
});
$row.html(rows); //Append them in the end
}
Demo
You could use $.map as well.
var $template = $('#template'),
$row = $('.row');
function display(friends) {
var rows = $.map(friends, function (friend) {
var templateHtml = $template.text().replace(/{{friendId}}/g, friend.id);
return templateHtml;
});
$row.html(rows);
}
A scalable solution would be to use a template engine and make the server returns JSON response.
Take a look at Handlebars.js http://handlebarsjs.com/

Categories