Dynamically created collapsible-set in jQuery Mobile - javascript

Okay, once i see the answer to this, I will feel stupid. I'm certain of that.
I've created this exactly the way I want to before, but I am refactoring my code for a new version right now. I am trying to dynamically create collapsible sets in jQuery Mobile, but my html does not render right.
<div data-role="header">
<h2>Playground</h2>
</div>
<div data-role="content">
<div data-role="button" id="addprimary" data-inline="true">Add 5</div>
<div data-role="collapsible">
<h4>Collapsible</h4>
<form id="makecollapsible">
</form>
</div>
</div>
<div data-role="footer">
<h4>Please, no applause</h4>
</div>
</div>
<script>
$('#addprimary').on('click', function () {
Markup.Collapsible();
});
var Markup = new Object();
Markup.Collapsible = function () {
$('#makecollapsible')
.append($('<div>')
.attr({ 'data-role': 'collapsible-set', 'id': 'primary' })
);
for (i = 0; i < 5; i++) {
($('<div>')
.attr({ 'data-role': 'collapsible', 'data-content-theme': 'c',
'data-collapsed': 'true' })
.html('<h4>' + i +'</h4>'))
.appendTo('#primary');
}
}
</script>
Could somebody please take a look at this http://jsfiddle.net/c2jLY/ and tell me what I have wrong? My <div>s with data-role='collapsible' are not rendering as collapsibles, which is also having an effect on the HTML I am trying to put in them later on.
Help is appreciated, thanks!

Inside Markup.Collapsible function and at the end of it, add the below. For collapsible-set, you need to tell jQM that you're enhancing a .collapsibleset() and combine it with .trigger('create').
$('#makecollapsible').collapsibleset().trigger('create');
Demo
I forgot to mention that when appending items dynamically, call enhancement methods on parent element; doing so, will enhance children elements. Thus, you don't need to use .collapsible().trigger('create') for each collapsible appended.

what i show here is a simple one but working:
<script type="text/javascript">
//dynamically make 10 collapsible items and append them to the collapsible-set
var jj = "SUPER item added..";
$('[data-role="content"]').append('<div id="set" data-role="collapsible-set"></div>');
var count;
for (count=0; count < 10; count++) { // div id should be from id='c0' to 'c9'
$("#set").append('<div id="c' + count + '" data-role="collapsible">');
$("#c" + count.toString()).append('<h3>Adding element_' + count +'</h3>');
$("#c" + count.toString()).append(jj + 'count ' + count + '</div>');
}
// either one is tested working below:
// $('[data-role="content"]').trigger('create');
$( "#set" ).collapsibleset( "refresh" );
</script>
<script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
<link href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<body>
<!------------------------page 1 ListView template-->
<div data-role="page" id="page01">
<div data-role="header" data-theme="b" data-position="fixed">
<h2>-- DEMO -- </h2>
</div>
<div data-role="content" id="content">
</div>
</body>

Related

toggle div using for loops

just wondering what went wrong.. i have two div named click_1 and click_2.. and i want to toggle the div named hide corresponding with their numbers.. lets say click_1 with hide_1 and click_2 with hide_2.. but when i ran the code only click_1 is functioning .. what seems to be wrong... newbie here.. recently learned jquery
<div id='click_1'>
<div id='hide_1'></div>
</div>
<div id='click_2'>
<div id='hide_2'></div>
</div>
<script>
function toggle_div(id_A,id_B){
for(var i=0; i<3; i++){
var new_A = id_A + i;
var new_B = id_B + i;
$(new_A).click(function(){
$(new_B).toggle();
});
}
}
toggle_div('click_','hide_');
</script>
The issue is because your id selectors are missing the # prefix:
toggle_div('#click_', '#hide_');
However you should note that you will also need to use a closure for this pattern to work otherwise the new_B element will always be the last one referenced in the for loop.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='click_1'>
click 1
<div id='hide_1'>hide 1</div>
</div>
<div id='click_2'>
click 2
<div id='hide_2'>hide 2</div>
</div>
<script>
function toggle_div(id_A, id_B) {
for (var i = 1; i < 3; i++) {
var new_A = id_A + i;
var new_B = id_B + i;
(function(a, b) {
$(a).click(function() {
$(b).toggle();
})
})(new_A, new_B);
}
}
toggle_div('#click_', '#hide_');
</script>
As you can see this is very verbose, rather complicated and hardly extensible. A much better approach is to use generic classes and DOM traversal to repeat the same logic on common HTML structures.
To achieve this put common classes on the elements to be clicked and the elements to toggle. Then in the single click event handler you can use the this keyword to reference the element which was clicked, then find() the element to toggle within that. Something like this:
$(function() {
$('.click').click(function() {
$(this).find('.hide').toggle();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="click">
click 1
<div class="hide">hide 1</div>
</div>
<div class="click">
click 2
<div class="hide">hide 2</div>
</div>
<div class="click">
click 3
<div class="hide">hide 3</div>
</div>
Also note that this pattern means that you can have an infinite number of .click elements with matching .hide content without ever needing to update your JS code.
It is better not to use for loop for click event ! If you have id like that your can handle by that clicked id split ....
$("[id^='click_']").on("click",function () {
$('#hide_'+this.id.split('_')[1]).toggle();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='click_1'>
Click1
<div id='hide_1'>hide1</div>
</div>
<div id='click_2'>
Click2
<div id='hide_2'>hide2</div>
</div>

Append element from another page?

Given this HTML:
index.html:
<div class="tile" data-tilename="test">
<div class="tileHeader">Tile Name</div>
</div>
tile-content.html:
<div id="test-tile" class="tileContent">
<!-- lots of stuff here. -->
</div>
How can I arrive at the following?
<div class="tile">
<div class="tileHeader">Tile Name</div>
<div class="tileContent">
//lots of stuff here.
</div>
</div>
Currently all these are created dynamically, so here is my current code:
let $elTile = $('<div/>', {
class: 'tile'
}).appendTo($elContainer);
let $elTileHeader = $('<div/>', {
class: 'tileHeader',
html: tile.header
}).appendTo($elTile);
let $elTileContent = $('<div>').load('tile-content.html #' + tile.name + '-tile');
$elTile.append($elTileContent);
The last two lines above were inspired by this solution. Unfortunately it adds an extra <div> which I would like to avoid:
<div class="tile">
<div class="tileHeader">Tile Name</div>
<div> <!-- I don't want this -->
<div class="tileContent">
<!-- lots of stuff here. -->
</div>
<div>
</div>
How can I arrive at the desired solution?
There are a couple similar questions, but none that I found have solutions and my situation is slightly different (dynamically created elements).
It's because you are creating that extra div by yourself here:
let $elTileContent = $('<div>').load(...)
You should load the content, then prepend the header:
//create the tile and add it to the container
let $elTile = $('<div/>', {
class: 'tile'
}).appendTo($elContainer);
//create the header but do not add it yet
let $elTileHeader = $('<div/>', {
class: 'tileHeader',
html: tile.header
})
//load the content into the tile
$elTile.load('tile-content.html #' + tile.name + '-tile', function(){
//on the "complete" callback, prepend the header
$elTile.prepend($elTileHeader);
});
Happy Coding :)
You are telling it to give that extra div on this line:
let $elTileContent = $('<div>).load('tile-content.html #' + tile.name + '-tile')
You would need to do the load on the element with the tile class first and then duse the .prepend instead of append for the header div element so it stacks above the loaded content div.

How to navigate through a dynamic created link?

So I have a table in HTML which gets filled dynamically with <td> elements. These elements are a link, but I don't know how to navigate through them.
My HTML:
<div id="catalog-page" data-role="page">
<!-- catalog header -->
<div data-role="header" data-id="header" id="catalog-header" data-position="fixed" class="ui-header">
Back
<h1>Pokémon Catalog</h1>
</div>
<!-- /catalog header -->
<div data-role="content">
<h1>Gotta catch em all!</h1>
<table data-role="table" id="table-column-toggle" data-mode="columntoggle" class="ui-responsive table-stroke">
<tr>
<th>Name</th>
</tr>
</table>
</div>
My JS file:
$(document).on("pageshow", "#catalog-page", function() {
console.warn("catalog-page loaded");
$.ajax({
url: "http://pokeapi.co/api/v2/pokemon/"
}).then(function(data) {
console.warn("Found " + data.count + " pokemon...");
console.warn(JSON.stringify(data.results));
var obj = data.results;
drawTable(obj);
function drawTable(data) {
for (var i = 0; i < data.length; i++) {
drawRow(data[i], i);
}
}
function drawRow(rowData, c) {
var row = $("<tr />")
$("#table-column-toggle").append(row);
row.append($("<td>" + rowData.name + "</td>"));
}
});
});
The results of this will be like:
Bulbasaur will have an id of pokemon0, ivysaur pokemon1, etc..
The problem is that if I click on Bulbasaur, I want the page to load a new div. In this div I want to provide information about the Bulbasaur. I am using Jquery mobile for the dynamic loading of the div.
In my HTML code:
<div id="pokemon0" data-role="page">
<div data-role="header" data-id="header" id="catalog-header" data-position="fixed" class="ui-header">
Back
<h1>Here comes the name of the pokemon</h1>
</div>
</div>
This works, but as you can see, I've written id="pokemon0", but that is not how I want it because otherwise I have to create 811 div's..
So long story short, is there a way to change id="pokemon0" to whatever link I am clicking (for instance id="pokemon12")?
You just need one div with generic id
<div id="pokemon" data-role="page">
Add click handler to your dynamic links
$("a[href^='#pokemon']").click(function(){
$('#pokemon h1').html($(this).text());
});
See working example here. By the way, it takes a long time to create 811 table rows.

how can I manipulate my HTML after reading my JSON file?

<script type="text/javascript">
window.alert = function(){};
var defaultCSS = document.getElementById('bootstrap-css');
function changeCSS(css){
if(css) $('head > link').filter(':first').replaceWith('<link rel="stylesheet" href="'+ css +'" type="text/css" />');
else $('head > link').filter(':first').replaceWith(defaultCSS);
}
$( document ).ready(function() {
$.getJSON("./data/data.json", function(json) {
console.log(json.length); // this will show the info it in firebug console
});
});
</script>
I know that json is my JSON object. I want to use that to manipulate my html
if it's the 1st item in my JSON object then
<div class="item active"> <!-- active only appears if it's the first item -->
<blockquote>
<div class="row">
<div class="col-sm-3 text-center">
<img class="img-circle" src="json[0].image" style="width: 100px;height:100px;">
</div>
<div class="col-sm-9">
<p>json[0].quote</p>
<small>json[0].person</small>
</div>
</div>
</blockquote>
</div>
and I want to repeat the above code n times
There are many ways to do this, but probably the easiest way would be to build a string and append it to whatever container you want it to live in.
$.getJSON("./data/data.json", function(json) {
$.each(json, function(data) {
var html = '<p>' + data.quote + '</p>' +
'<small>' + data.person + '</small>';
$('#MySuperSpecialDiv').append(html);
});
});
Please note that this won't scale well. If you are going to add much more markup than you already have, you should really consider some sort of templating alternative.
Also, if some one comes in behind you to maintain this project, you probably won't be their favorite person.

FirefoxOS emulator and JSFiddle giving different result

I have the following code:
http://jsfiddle.net/xFzy8/4/
HTML:
<body>
<!-- ..................... Page 1 - HOME ..................... -->
<!-- ......................................................... -->
<div data-role="page" id="home">
<div data-role="header" data-position="fixed">
<h3>My Test App</h3>
</div>
<div data-role="content">
<div class="container-wrapper">
<!--
..................FOR TESTING ONLY..................
<div class="container">
<div data-role="collapsible" id="coll1">
Delete
<h3>Item 1</h3>
<p>This is item 1</p>
</div>
</div>
..................................................
-->
</div>
</div>
</div>
</body>
CSS:
.btn-delete{
position:absolute;
top:0;
right:2px;
display:block !important;
z-index:10000;
}
.ui-collapsible {
position: relative;
}
Javascript:
$(document).ready(function() {
var $containerWrapper = $('.container-wrapper');
/*..............FOR TESTING...................
//var $btnDelItem1 = $('#delColl1').detach();
//$('#coll1').append($btnDelItem1);
..............................................*/
for(var i=1; i<=5; i++) {
var $containerDiv = $('<div>', {'class':'container'})
var $divCol = $('<div>', {'data-role':'collapsible', 'id':'coll'+i});
var $btnDel = $('<a>', {'href':'#', 'class':'btn-delete ui-btn ui-icon-delete ui-corner-all ui-btn-icon-notext', 'id':'btnDel'+i});
var $colHead = $('<h3>', {'text':'Item '+i});
var $colContent = $('<p>', {'text':'This is item '+i});
$containerDiv.append($divCol);
$divCol.append($colHead);
$divCol.append($colContent);
$containerWrapper.append($containerDiv);
$containerWrapper.trigger('create');
$divCol.append($btnDel);
}
});
I am using the same code to run the webapp on firefoxOS emulator. But i am getting a different result. This is the result i'm getting on the emulator:
http://imagizer.imageshack.us/v2/800x600q90/208/mzv6.jpg
On JSFiddle, the Delete icon is appearing as it should. But on the emulator, the delete button is appearing below the collapsible headers. Even when i open the 'index.html' in a normal browser, im getting the same result as in the emulator.
How do I fix this?
Thanks!
Try these 2 things:
1 put the btn-delete class at the end of the list instead of first in the list of classes and see if it makes any difference.
2 Instead of the class, just use jQuery to set the CSS. After appending the created DOM elements, run this:
$btnDel.css({"position": "absolute", "top": "0", "right": "2px", "zIndex": "10000"});
Here is your updated FIDDLE
Also, instead of jQuery document.ready, use one of the jQM init events like:
$(document).on("pageinit", function() {...
If jQM is still overriding your class, try appending the DOM elements in pageinit, and then set the CSS in pageshow.

Categories