Sepodati Posted July 25, 2017 Share Posted July 25, 2017 So what I have works fine, but I have a feeling there's a more efficient or straight-forward way to accomplish this. What I have is this div and the inner <li> will need to be repeated based on the data returned from a JSON query to a PHP script. <div class="notification" id="notification"> <span id="no_config_notice" style="display:none;">No emulator configuration is currently set on any interface.</span> <ol id="config_notice" style="display:none;"> <li style="line-height:2em;font-style:italic;">Current Emulator Configuration:</li> <li id="interface_config"> <span class="delete" id="{interface}">✖</span> <span>Interface <{interface}>: </span> <span id="delay">delay {delay}{delay_unit} </span> <span id="jitter">jitter {jitter}{jitter_unit} </span> <span id="loss">loss {loss}% </span> <span id="rate">bandwidth {rate}{rate_unit}</span> </li> </ol> </div> Based on the data, the list of (one or more) interfaces may or may not need to show each of those <span> elements. If there is no loss or rate setting, for example, I don't want those elements shown. A sample of the data returned: {"enp0s3":{"delay":500,"delay_unit":"ms","rate":"12","rate_unit":"Mbit"}}Finally, the JQuery code that runs the template replacement. More than one interface could be returned, hence the .each() loop. function load_status(data) { var count = 0; hide = "style=\"display:none;\""; html = $("#interface_config").html(); $("#interface_config").remove(); $.each(data, function(index, info) { output = html.replace(/{interface}/g, index); if(info.delay === undefined) { output = output.replace(/id="delay"/g,hide); } else { output = output.replace(/{delay}/g, info.delay); output = output.replace(/{delay_unit}/g, info.delay_unit); } if(info.jitter === undefined) { output = output.replace(/id="jitter"/g, hide); } else { output = output.replace(/{jitter}/g, info.jitter); output = output.replace(/{jitter_unit}/g, info.jitter_unit); } if(info.loss === undefined) { output = output.replace(/id="loss"/g, hide); } else { output = output.replace(/{loss}/g, info.loss); } if(info.rate === undefined) { output = output.replace(/id="rate"/g, hide); } else { output = output.replace(/{rate}/g, info.rate); output = output.replace(/{rate_unit}/g, info.rate_unit); } $("#config_notice").append('<li>'+output+'</li>'); count++; }); if(count==0) { $("#no_config_notice").show(); } else { $("#config_notice").show(); } } function ajax_getInterfaceStatus() { $.ajax({ url: "tacem.php", data: { action: "status"}, method: "POST", dataType: "json", success: load_status }); } This just doesn't feel right, though, since there's CSS & HTML in my javascript code as strings. Like I said, this works, but is there a more efficient way to do it? I'll eventually be adding more <span> components to the display, as there are still about 10 more interface elements that may or may not be set. -John Quote Link to comment https://forums.phpfreaks.com/topic/304411-jquery-repeating-a-templated-efficiently/ Share on other sites More sharing options...
Jacques1 Posted July 25, 2017 Share Posted July 25, 2017 Use the DOM API to change attributes and element contents instead of messing with the raw HTML markup -- which is not only ugly but also dangerous. There are also dedicated JavaScript template engines like Handlebars.js, so all the repetitive search-and-replace can be replaced with a single function call. Quote Link to comment https://forums.phpfreaks.com/topic/304411-jquery-repeating-a-templated-efficiently/#findComment-1548876 Share on other sites More sharing options...
Sepodati Posted July 25, 2017 Author Share Posted July 25, 2017 (edited) I'll check out Handlebars. Thanks. How would that work with the DOM API? Is that still through JQuery or something else? I understand that this gets me the raw HTML: html = $("#interface_config").html(); Is there a way to turn that back into (or get it originally) as an object that I can .show() or .hide() the elements I want and then append it to the list? I saw some parse functions referenced in JQuery, but I haven't played with them, yet. If I can do all that, can I just set the .val() for the <span> instead of search & replace? This is all new to me within the past week, so there's a lot that I "don't know that I don't know" at this point. Edited July 25, 2017 by Sepodati Quote Link to comment https://forums.phpfreaks.com/topic/304411-jquery-repeating-a-templated-efficiently/#findComment-1548878 Share on other sites More sharing options...
kicken Posted July 25, 2017 Share Posted July 25, 2017 (edited) Give your elements classes rather than ID's so you don't have to deal with the "id's must be unique" problem, then just query for them after transforming your template. Something like this: <div class="notification" id="notification"> <span id="no_config_notice" style="display:none;">No emulator configuration is currently set on any interface.</span> <ol id="config_notice" style="display:none;"> <li style="line-height:2em;font-style:italic;">Current Emulator Configuration:</li> <li id="interface_config"> <span class="delete" id="{interface}">✖</span> <span>Interface <{{interface}}>: </span> <span class="delay">delay {{delay}}{{delay_unit}} </span> <span class="jitter">jitter {{jitter}}{{jitter_unit}} </span> <span class="loss">loss {{loss}}% </span> <span class="rate">bandwidth {{rate}}{{rate_unit}}</span> </li> </ol> </div> <script type="text/javascript"> function loadStatus(data){ var output = []; var template = Handlebars.compile($('#interface_config').html()); $('#interface_config').remove(); $.each(data, function(index, info){ info.interface = index; var html = template(info); var $result = $($.parseHTML('<li>' + html + '</li>')); if(info.delay === undefined) { $result.find('.delay').hide(); } if (info.jitter === undefined){ $result.find('.jitter').hide(); } if (info.loss === undefined){ $result.find('.loss').hide(); } if (info.rate === undefined){ $result.find('.rate').hide(); } output.push($result.wrap('<li></li>')); }); if (output.length){ $('#config_notice').append(output).show(); } else { $('#no_config_notice').show(); } } </script> Edited July 25, 2017 by kicken 1 Quote Link to comment https://forums.phpfreaks.com/topic/304411-jquery-repeating-a-templated-efficiently/#findComment-1548879 Share on other sites More sharing options...
Sepodati Posted July 25, 2017 Author Share Posted July 25, 2017 Thank you for that. I think the parseHTML() bit is what I was missing. That'll turn it back into an object I can work with in jquery instead of writing raw HTML. Handlebars will certainly make the templating easier, too. Thanks again. -John Quote Link to comment https://forums.phpfreaks.com/topic/304411-jquery-repeating-a-templated-efficiently/#findComment-1548886 Share on other sites More sharing options...
Sepodati Posted July 25, 2017 Author Share Posted July 25, 2017 That was plug and play and it worked. Awesome. Quote Link to comment https://forums.phpfreaks.com/topic/304411-jquery-repeating-a-templated-efficiently/#findComment-1548887 Share on other sites More sharing options...
Sepodati Posted July 26, 2017 Author Share Posted July 26, 2017 (edited) Just to share on this, I did make a few changes in the final result. Marked with >> below, this removes the little bit of writing <li> HTML strings in the code function load_status(data) { var output = []; var template = Handlebars.compile($('#interface_config').html()); $('#interface_config').remove(); $.each(data, function(index, info){ info.interface = index; var html = template(info); >> var $result = $("<li>").append($.parseHTML(html)); if(info.delay === undefined) { $result.find('.delay').hide(); } if (info.jitter === undefined){ $result.find('.jitter').hide(); } if (info.loss === undefined){ $result.find('.loss').hide(); } if (info.rate === undefined){ $result.find('.rate').hide(); } >> output.push($result); }); if (output.length){ $('#config_notice').append(output).show(); } else { $('#no_config_notice').show(); } }Also figured out (after lots of trial and error) how to register the click event for my delete "button". <span class="delete" id="{interface}">✖</span> $("#config_notice").on("click", ".delete", function() { id = $(this).attr("id"); alert(id); });Maybe there's a better way; I dunno. This will get me the interface name as "id" that I can pass to a delete function in my PHP script, though. So it'll work for me for now. Edited July 26, 2017 by Sepodati Quote Link to comment https://forums.phpfreaks.com/topic/304411-jquery-repeating-a-templated-efficiently/#findComment-1548908 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.