saint
saint

Reputation: 268

Performing calculations on dynamically generated rows (jQuery)

I am trying to perform some calculations on some dynamically generated rows in my table.The dropdowm options all carry numerical values and based on the values the RiskOfObsctacle and ValueOfObstacle will be calculated:
ValueOfObstacle= LikelihoodSeverityPrincipal;
RiskOfObsctacle= Likelihood*Severity;

I dont have any problem adding/deleting rows but the problem is displaying the results after values are entered.

Here is my jquery code for generating the rows:

function addRow(tableID) { 

var table = document.getElementById(tableID);

var rowCount = table.rows.length;
var row = table.insertRow(rowCount);

var cell1 = row.insertCell(0);
var element1 = document.createElement("input");
element1.type = "checkbox";
element1.name="chkbox[]";
cell1.appendChild(element1);

var cell2 = row.insertCell(1);
cell2.innerHTML="<textarea name='Obstacle[]' cols='20'>";

var cell3 = row.insertCell(2);
cell3.innerHTML = "<select name='Likelihood[]'> onKeyup='calc() <option value='1'>Low</option> <option value='2'>Medium</option><option value='3'>High</option>/>";

var cell4 = row.insertCell(3);
cell4.innerHTML = "<select name='Severity[]'> onKeyup='calc() <option value='1'>Low</option> <option value='2'>Medium</option><option value='3'>High</option>/>";

var cell5 = row.insertCell(4);
cell5.innerHTML = "<select name='Priority[]'> onKeyup='calc() <option value='1'>Low</option> <option value='2'>Medium</option><option value='3'>High</option>/>";

var cell6 = row.insertCell(5);
cell6.innerHTML = "<input type = 'text' name='Principal[]' required placeholder='100.3' onKeyup='calc()'>";

var cell7 = row.insertCell(6);
cell7.innerHTML = "<input type = 'text' name='ObsRisk[]'  readonly value onKeyup='calc()'>";


var cell8 = row.insertCell(7);
cell8.innerHTML = "<input type = 'text' name='ObsValue[]' readonly onKeyup='calc()'>";

}

And here is the code for performing calculations:

function calc (){
$('.Likelihood, .Severity, .Principal').change(function(){
var value = 0;
var $row = $(this).closest("tr");
var like = parseFloat($row.find('Likelihood').val());
var sev = parseFloat($row.find('Severity').val());
var prin = parseFloat($row.find('Principal').val());
value = like*sev*prin;
if (isNaN(value)) {
$row.find('.ObsValue').value("Nix is");
}
else{
$row.find('.ObsValue').val(value);
}
calc();
});
}

Also based on the results the color of the text should change i.e. green if positive and red if negative. Thanks for the help.

Obstacle Table

Please, let me know if more info is needed!

Upvotes: 0

Views: 1398

Answers (1)

Daved
Daved

Reputation: 2082

You have a couple things going on in here.

  1. Your markup should be cleaned up a bit to add classes to the items to reference them in the rows. Having "class='Likelihood'" will allow you to reference the elements.

  2. Your calc function should be a handler for a change event binding. Also, in the calc event, you have a couple jQuery syntax errors like your "find('Severity')" and ".value()" calls.

  3. I can't see it here in your sample, but make sure you are binding all of this in the "ready" event for jQuery. Otherwise, if this is in the head of the page, you are trying to bind to the elements before they exist. And...

  4. You should use jQuery ".on" to bind the change event handler to the table so it works for dynamically added elements like the following:


$(function() {    // jQuery ready shorthand
    $('#myTable').on('change','.Likelihood,.Severity,.Principal', function(e) { 
        /* something */ 
    }
});

All that said, I put together two fiddles for you to clean it up and show it working. The first one is just a copy of what you put with a few things cleaned up to make it work. I added the classes, cleaned up some of the syntax errors, and then bound the events in the ready handler. The "onkeyip" is still there, but not being used. I also left "calc" as it's own function if you wanted to use it from other elements, but the contents really could be an anon function as the handler for the change event.

The second fiddle is a little different. What you are doing, just from what I can see, lends itself really well to templating and data-binding. I used the JSViews package, with JSRender, and JSObservable and included your markup as a template in the page. It takes a little getting used to, but it's nice for UI work and makes managing markup like you are rendering much easier since it's actually HTML with data-binding (data-linking for JSViews). You can read up on it here: http://www.jsviews.com/#home

Basically, you can create objects and arrays and bind them and their properties to elements in a page or template for dynamic rendering. If you have heard of Model View View Model (MVVM) it's what helps make it work. With two-way binding, any changes to the UI in terms of inputs or similar, changes the object or array (model). Any changes to the model via script is displayed in the template (view). It can get pretty complex, but your situation lends itself to a fairly good one for starting. It makes it nice to add to, remove from, and modify objects or an array of objects. In the example I provided, the add and remove just update the model with a new empty object, for example, but the UI updates with a new table row. And the template for the row is stored in a script tag in the HTML so it's really easy to work with.

Anyways, after all that and my .02 cents, below are the links. Ask questions and pick what's easiest for you. However, if you do much work with dynamic rendering of large blocks of HTML, look into templating.

Fiddle for original: http://jsfiddle.net/Hps25/

Fiddle for templating: http://jsfiddle.net/sW33n/2/

Update: If you use the templating method, the data for the obstacles is already constructed into a single array of objects based on the rows created. That's the great thing about the templating approach: you add a row, it adds an item to the array. Then, when you want to use it, you just use the array, in this case obstacles. This, then, makes it super easy to use for posting to a service to update items in a DB, for instance. Using AJAX you can pass an object as "data" that will get serialized into a string. Deserialize it at the server into an object and you can do what you wish.

I updated the fiddle to show an example of this, passing the obstacles array along with a single value from a "made-up" select element. Obviously the serverside piece would still need to be defined.

Updated Fiddle: http://jsfiddle.net/sW33n/4/

Upvotes: 2

Related Questions