JQuery Passing values into .Each() callback - javascript

This is a pretty simple (Well simple to the point that I am not sure how to make it work) little issue.
I have an object that contains an array of data that I need to utilize inside my each statement and to my surprise... I can't just directly reference it. I have read that specifying an
var something = this;
before the if would allow it to be called and that was no good.
Current Code:
var exsistingshifts = response.data.ExsistingEvents;
var eventdata = this;
$(".shiftdiv").each(function (index) {
var currdiv = $(this).children();
var info = eventdata.exsistingshifts;
})
Expected result info = my array of delicious data
Current result info = undefined
For people wanting Context, shiftdiv class divs are built dynamically by a query and have a data value in their ID that link them to a certain set of events. The array contains ALL events and their data keys, so for each shift div I need to capture the ID which is easy enough, compare it to the array and pluck out the values I need from that array to mess with that particular div.
As for page context of the $(this) this is being called inside of an onclick function. The onclick function sets response.data.ExsistingEvents

If I am not wrong , you are using this code inside ajax Success function (I can see response object so.)
Now if you are doing so, you are doing a mistake by assigning this object to eventdata.
line var eventdata = this will store $.ajax object in eventdata,
and this object (means that your ajax object) doesn't contain any value for key exsistingshifts , So eventdata.exsistingshifts is undefined.
change your code to following should work
$(".shiftdiv").each(function (index) {
var currdiv = $(this).children();
var info = response.data.ExsistingEvents[index].exsistingshifts;
});

Related

Changing local variable in JavaScript affects original global with different name

I have a global declared at top of script:
var g_nutrition_summary = null;
When the user enters the page, I return network data and give this variable a value.
g_nutrition_summary = json.data;
This line is the ONLY assignment of the variable and is never called again (tested with alerts).
I later use that json.data variable to populate a Bar Chart with the plugin Chart.js. The global assignment is for later use.
Underneath the chart, the user can filter certain types of data it displays with a series of checkboxes. So my goal is, to keep an original value of what comes in from the network, and then make a LOCAL COPY of it and alter the COPY (not the global original) and repopulate the chart. Everytime the user checks/unchecks a checkbox, it will call this function and grab the ORIGINAL global (g_nutrition_summary) and re-filter that.
Here is how I do it:
function filter_nutrition_log()
{
alert("1: " + JSON.stringify(g_nutrition_summary));
// reassign object to tmp variable
var tmp_object = g_nutrition_summary;
var food_array = new Array("Grains", "Vegetables", "Fruits", "Oils");
var checked_array = new Array();
// Make an array of all choices that are checked
$(".input-range-filter").each(function()
{
var type = $(this).val();
if ($(this).is(':checked'))
{
checked_array.push(type);
}
});
alert("2: " + JSON.stringify(g_nutrition_summary));
// Loop thru all the 7 choices we chart
$.each(food_array, function(i, val)
{
// find out if choice is in array of selected checkboxes
if ($.inArray(val, checked_array) === -1)
{
// it's not, so delete it from out tmp obj we
// will use to repopulate the chart with
// (we do not want to overwrite the original array!)
delete tmp_object["datasets"][val];
}
});
// Resert graph
alert("3: " + JSON.stringify(g_nutrition_summary));
getNutritionChart(null, tmp_object, null, false);
}
Somehow, between alert "1" and alert "2". The global gets changed. Then when the user clicks a checkbox again and it calls this function, the very first alert shows that the original, global object contains the altered data to the tmp_object variable.
As you can see, I call a third party function I have created when this happens originally. Doing a search for the global there is absolutely nowhere else it is used in the instances described above.
Am I not understanding something about JavaScript variable scope?
Both objects and arrays in javascript are treated as references, so when trying to pass them to functions or to "copy" them, you are just cloning the reference
To have a "real copy", you would need to traverse the object and copy its content to another object. This can be done recursively, but fortunately jquery already comes with a function that does this: $.extend
So the solution would be:
var tmp_object = $.extend({},g_nutrition_summary);
If you have a nested object, you need to set an extra parameter:
var tmp_object = $.extend(true,{},g_nutrition_summary); // now it will do it recursively
For arrays, an easy way to make a "real copy" is, as #Branden Keck pointed out,
var arrCopy = arrOriginal.slice(0)
More on jquery extend: https://api.jquery.com/jquery.extend/
Going along with juvian's comment. To create the new array as somewhat of a "copy" and not just a reference, use:
var tmp_object= g_nutrition_summary.slice(0);
However, .slice() is only works for arrays and will not work on JSON, so to used this method you would have to create an array from the JSON
Another method that I found (although not the cleanest) suggested creating a string from the JSON and re-parsing it:
var tmp_object= JSON.parse(JSON.stringify(g_nutrition_summary));

Reading an object's value in JavaScript

I want to get the features from my layer. So I'm requesting WMSGetFeatureInfo method after a successful request for GetFeatureInfo on my layer.
The returned object is structured like this:
I can read values like BEVDICHTE with var bevdichte = features.BEVDICHTE and so on.
But when I want to get the value of the_geom with var the_geom = features.the_geom it returns an object. Yes it is nested so this is intended but my question is how to get the value ol.geom.MultiPoint
from the_geom?
EDIT:
Unfortunately var target = features.the_geom['actualEventTarget_']; will just return another 'actualEventTarget_' object. This is because the the_geom object is nested into infinity. I attached another screenshot to describe my problem. There are many more nested eventTargets following. Yet I was not able to get the property ol.geom.MultiPolygon.
To access a nested array, just use brackets: '[ ]'
var nestedArray = [[1,2], [3,4]];
var nestedArrayValue = nestedArray[0][0];
// --> returns 1
With your example:
var target = features.the_geom['actualEventTarget_']
By the way, from the looks of it var the_geom = features.the_geom doesn't seem like an array. It has keys, mapped to a value, are you sure this is an array, not an object?

Need to duplicate code, but rather instantiate several objects and keep the code in one place

I've developed some javascript which generates a dynamic table from an array, then allows the user to edit the data. This works perfect.
Now I want to do use this code 3 times on the same HTML page. At the moment it depends on two variables: metadata, which describes the header format and is read only and the same for all three occasions, and 'data' which actually holds the data for the table.
Rather than having three copies of the code for each instance, I'm thinking it would be better to have an object which keeps everything internal and simply has 'setData' and 'getData' methods.
Existing code dynamically creates onclick events - how to get these to reference the objects function, rather than a global function? (ie, there is currently functions like 'RemoveRow(index)', which I assume will be 'obj.RemoveRow(index)'. I would love to do this in jquery but alas, I wouldn't know the rowindex to pass in then, unless someone has a solution. Perhaps store it somewhere inside the DOM and access it somehow to determine the row being clicked on?
Is it possible to pass a reference to an array? It would be much better if the object could manipulate the array passed in rather than making a copy to work on and then the caller having to copy that back to its own array.
So this is very raw code and only one of multiple options, but maybe you get the idea:
Create an object that handles a single table
function TableControl () {
// dom elements
this.table = null;
this.rows = null;
// values
this.id = null;
// create new row
this.insertRow = function() {
// some logic
this.table.append( 'new row goes here' );
},
// load table object and rows and stuff
this._initiate = function() {
//create object with all passed arguments
var args = arguments[0] || {};
// set internal values
this.id = args.id;
// get dom elements
this.table = $('#' + this.id);
this.rows = this.table.find('tr');
},
this._initiate( arguments[0] );
}
Create instances of that object using the id of each table
var table_1 = new TableConrol({ id: 'table_1' });
var table_2 = new TableConrol({ id: 'table_2' });
var table_3 = new TableConrol({ id: 'table_3' });
So each table handles only stuff within it's own "scope", like adding new rows for example:
table_1.insertRow();

Create object property names using loop and input textboxes

I am refactoring some code where I grab the values inputted into textboxes and use said values for calculations. The problem is rather than using document.getElementByID multiple times I want to loop through each textbox on the page and assigning each value to this object which I will pass to my calculation functions. I would also like to set the property names of this object by looking at the input textbox IDs and using the ID strings for the object property names.
See code below:
$(document).ready(function() {
var calcObj = new Object();
$("input[id^='txt']").each(function(i, val) {
calcObj[i] = this.value;
});
$.each(calcObj, function(i, val) {
// alert(val);
});
});
As you can see when document is ready, object is created. There is a jquery .each loop to go through every input with id that contains txt. I am assigning this.value to object where index is i.
So I want to some how name the properties of this object and assign value so I can reference object property name elsewhere in the code where I pass this object to another function.
Thanks.
As far as I understand, you want:
calcObj[this.id] = this.value;
I don't exactly get what you're asking for, because it seems like you're already doing what I think you're asking.
Right now, you're doing:
calcObj[i] = this.value;
That's no different from assigning it like:
calcObj['foo'] = this.value;
// and later we can access that via
alert( calcObj.foo ); // or calcObj['foo']
You can be dynamic with that as well, like:
calcObj[this.id] = this.value;

How do you set a variable to be an empty, but workable Jquery object?

Outside of a for I declare a variable using var list;. I use this variable inside of my for loop like so:
// add the html to the list
if (list == undefined)
list = item;
else
list.append(item.contents());
item is a cloned jquery object build from a $('list_template').clone(); call (list_template is a div with <li> elements inside). What I am doing is creating a list, which I will then appendTo() where I need it.
Right now this code works fine, but it doesn't seem right to me. Unfortunatly, I cannot seem to figure out how to correctly declare the list variable to be an empty Jquery object. I have tried both:
var list = $([]);
var list = $('');
Both of those cause the append to not work correctly (or as expected) with list.html() being null. Is there a way to initialize my variable to an empty jquery object, so all I have to do is list.append(item.contents()); without the if/else statements?
Edit: Ok to lessen confusion here is the whole javascript function that currently works fine:
var list;
// Loop through all of the objects
var objects = data.objects;
for (x = 0; x < objects.length; x++) {
// Clone the object list item template
var item = $("#object_item_list_template").clone();
// Setup the click action and inner text for the link tag in the template
item.find('a').bind('click', { val: objects[x].Id }, function (e) { ShowObjectDetails(e.data.val); })
.html(objects[x].Name);
// add the html to the list
if (list == undefined)
list = item;
else
list.append(item.contents());
}
// set the list of the topics to the topic list
$("#object_list").empty();
$('<ul>').appendTo("#object_list").append(list.contents());
The object list template is as follows:
<div id="object_item_list_template" style="display:none">
<li class="object_item"></li>
</div>
This all works correctly by cloning the list item, setting up the click action, and adding it to the list on the display.
I am trying to get rid of the if/else statement. I can't just do list.append() because if list is undefined (or not a Jquery object), it throws an exception.
An empty jQuery object is declared as:
$();
Docs for jQuery object creation: http://api.jquery.com/jQuery/
EDIT:
It sounds like you're trying to eliminate the if/else statement by extending list whether or not it has any content.
Is that right?
If so, try something like this:
list = $( list.get().concat(item.get()) );
or
$.extend(list, item);
(Assumes list is starting out as an empty jQuery object.)
EDIT:
Since you're creating elements in a loop, you can always push() then into a jQuery object.
Try something like this:
var list = $(); // Start off with empty jQuery object.
...
list.push(item.find('li').get(0)); // A jQuery object is an Array. You can `push()` new items (DOM elements) in.
...
('<ul>').appendTo("#object_list").append(list);
(I edited from the original to only push the DOM element into the jQuery object.)
Should add the current item in the loop to your list.
You could eliminate the find() calls in your code if you just cloned the children of #object_item_list_template:
$('li', '#object_item_list_template').clone(); // Clone the `li` without the `div`.
Now you have a clone of the li itself. No need to do a find.

Categories

Resources