Alternatives to comparing object property using if...else - javascript

I hope I make my question clear.
I have a few objects which I have created with a property called address. For example, Obj1 has address 0x0000, Obj2 has address 0x0004 and so on.
There is a list of random input addresses which I need to process. Once the input address is one of the object address (if addr=0x0000||addr=0x0004....), then a function will be automatically loaded.
Currently, I am comparing it by a list of Object addresses, which I think is a waste of iteration. Is there any way, I can access it by index? For example, once I enter an input address of 0x0004, a function will be run directly.
edit : Thanks for all your answers :) I have a clearer idea now

You got 2 choices:
Use switch to define all functions:
switch (input){
case '0x0000': function(input){}; break;
case ...
}
Use a predefined map:
var functionMappings = {
'0x0000': function_1,
'0x0001': function_2,
};
if(functionMappings[input]) {
functionMappings[input](input);
}
I would prefer the second example, because it can be created dynamically in the runtime.
Update:
You can create your functionMappings dynamicaly like this:
var functionMappings = {// create first entries, or defualt functions
'0x0001': function_1,
'0x0002': function_2
};
if(condition_x) { // add new or overwrite existing functions
functionMappings[0x0005] = function_5;
}
Because this is an map, you can even overwrite default function definitions, if you need.

Iterate once and put all addresses as keys to an object:
var addresses = {};
for(var i=0;i<objList.length;i++){
addresses[objList[i].addr] = {};
addresses[objList[i].addr].fn = correspondingFunction
// you can even attach the corresponding object to it
// addresses[objList[i].addr].obj = addresses[objList[i].addr];
}
I use a loop for the example but you can do it any way that suits you
Then you have a list of your objects keyed by their address, and you can fetch them by it:
function getAddrFunction(addr){
if(addresses[addr] !== undefined){
return addresses[addr].fn;
}
return null;
}

Related

How to set default module params in Javascript

so i'm trying my hands on writing my very first library module using pure javascript except that i just hit a snag and need a little bit of help.
I'm using Revealing module pattern because of its neatness. In my module i have my default params in an object like this.
var defaults = {
name : 'John Doe',
age : 'Unspecified,
height : '5feet'
};
And this works splendid, but i have an init function where a user can pass an object with these keys. e.g
Module.init({
name : 'james',
age : 12
});
Now in my code, i try to write a function that returns the values of each of these keys comparing the default values and the initialized one. If the key/value exists initialized, it should return it else use default. I know what i want, but don't know how to check the objects keys just yet.
function getValues (defaultObject, initObject){
//scans the keys and returns the values
}
So in code i can do stuff like
var options = getValues(defaultObject, initObject);
var name = options.name;
This means that name will either be james if specified or john doe if not. Also for height since i didn't set a value, i get the default too
Thanks in advance guys.
What you need to do to compare both objects keys, and if the new object has a key, then replace the value in the old one. Here's an example:
function getValues(defaultObject, initObject) {
for (var key in initObject) {
if (initObject.hasOwnProperty(key)) {
defaultObject[key] = initObject[key];
}
}
return defaults;
}
I hope this help you.
See my answer in another thread how to
better define function optional default params : https://stackoverflow.com/a/52082835/1422407
It may help you to redefine function signature, and as result less useless logic in function itself.

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));

how to create a map in javascript with array of values dynamically

I have this requirement. Depending on the number of arguments passed in the function, I need to create that many entries in my map. Say I have a function myfunc1(a,b,c) , I need to have a map with the keys as "a","b" and "c" and I can have more than one values for each of the keys. But the problem is that I do not know beforehand, how many values will come for those keys. As and when the values come, I need to add them to the list of values corresponding to the matching key in the map. How do I do this in javascript? I have found static answers like below. But I want to do this dynamically. Can we use the push method ?
var map = {};
map["country1"] = ["state1", "state2"];
map["country2"] = ["state1", "state2"];
I think this is what you are asking. addValueToList will create array/list dynamically if the key is not present in the map.
//initially create the map without any key
var map = {};
function addValueToList(key, value) {
//if the list is already created for the "key", then uses it
//else creates new list for the "key" to store multiple values in it.
map[key] = map[key] || [];
map[key].push(value);
}
You can use the arguments list to populate your object with key corresponding to the strings passed in as arguments. Then you can write another function to populate this map with data.
var createMap = function() {
var map = {};
Array.prototype.slice.call(arguments).forEach(function ( arg ) {
map[arg] = null;
});
return map;
}
So createMap('para1', para2', para3') will return an object with 3 keys: para1, para2, para3. All having null as value. You can obviously replace null with a reference to the data you want the key to have, if you want to do it all in one function.

Comparing and interlacing variables for editing purposes with AngularJS

I have a list of names (staff in stafflist) from which I select some names and add them as an object to an array (paxlist). This operation is repeated, so several objects with different names are added into the array.
What I am attempting to do is to be able to edit each one of this objects to add or remove names.
For UX reasons, when I first select names from stafflist, they turn blue, and they reset to white when the object is added.
Basically, the effect/functionality I'm looking for is:
The object is added -> The main list resets
The edit button from one of the objects is clicked
The list of names of the object is compared with the main list, and the relevant names are highlighted (in blue) as existing/already selected names.
The user selects or deselects names.
The edition is completed, the resulting object saved and the main list reset.
I have a Plunkr depicting the addition functionality, but I don't see clear how could I compare and make the 2 variables (stafflist and pax in recordlist) work together as to edit the result.
I'm not specially looking for somebody to do it and solve this for me, but more to understand the logic behind a possible solution, as so far I can't think of anything...
Any comments will be highly appreciated!
I created a new Plunk with what I think you were trying to accomplish. Basically I just added a new state (editMode) which captured the pax being edited.
var editMode;
$scope.editRecord = function(record) {
editMode = record.pax;
$scope.stafflist.forEach(function (s) {
s.chosen = false;
});
record.pax.forEach(function(p) {
$scope.stafflist.forEach(function (s) {
if(p.name === s.name) {
s.chosen = true;
}
});
});
};
I then used this new state to figure out whether I was creating a new record or editing an existing one.
$scope.pushStaff = function (staff) {
staff.chosen = true;
var arr = editMode || $scope.paxlist;
arr.push(staff);
};
$scope.unpushStaff = function (staff) {
staff.chosen = false;
var arr = editMode || $scope.paxlist;
var index=arr.indexOf(staff);
arr.splice(index,1);
};
I'm sure there are cleaner approaches, but this is one way to do it.

Dynamically add variable name as part of object in Javascript/jQuery

I'm trying to create an object which references a number of forms which I can JSON.stringify() to send through to a validation script with a single AJAX request, but I can't seem to properly name the array inside the object, which should be an incrementing count as the number of arrays (forms) increases.
i.e.
var images = new Object();
var i = 0;
// loop through every form
$('form').each(function() {
var form = $(this);
images[i].name = form.find('input[name="name"]').val();
images[i].description = form.find('textarea[name="description"]').val();
// etc.
i++;
});
So, when complete after say two to three iterations (that is, it's gone through two-three forms), I have a Javascript object similar to this (written in pseudocode, I'm not exactly too sure how it's actually outputted):
images {
0 {
name : 0thImageNameValueHere,
description : 0thImageDescripValueHere,
etc : etc
}
1 {
name : 1stImageNameValueHere,
description : 1stImageDescripValueHere,
etc : etc
}
}
But, right now, Firebug is giving me a SyntaxError: missing ; before statement error, centered around this line:
images[i].name = form.find('input[name="name"]').val();
Now, I can change the 'value' of images[i].name to anything I like (images[i].name = 'yes') and I still get the same error. Syntactically I'm not missing any semi-colons, so it can't be that. Is it possible I'm not declaring my object correctly?
Images is an array ([]). Your syntax does not comply with this situation (you expect an object). Create an object for each item in the array, then you can assign values to the attributes of this object.
Also, you can just make use of the index parameter provided by jQuery, you don't have to create your own iterator.
This does what you want:
var images = []; // create an array
$('form').each(function( index ) {
var form = $(this);
// create object with {} object notation
var image = {
name: form.find('input[name="name"]').val(),
description: form.find('textarea[name="description"]').val()
};
images[index] = image; // append object in array position index;
}
See for more info on objects the JSON WIKI.
See for more info on arrays W3Schools.
I don't know about any missing semi colon, but you need to create an object at images[i] before you assign any properties on it. Ie try this:
images[i] = {
name: get('input[name="name"]').val(),
description: get('textarea[name="description"]').val()
};
You can also use the index parameter supplied by each():
$('form').each(function(i) { ... }

Categories

Resources