Jump to content

JQuery - Repeating a templated <li> efficiently.


Sepodati

Recommended Posts

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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>
Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.
Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.