How to re-label Object in array? - javascript

Extending a previous question about JavaScript and jQuery, I'm trying to make an array and then look into it, but the array contains dimensions and I can't get it right..
var markers = [];
$.getJSON('GetList', "id"= + data.id,
function(data){
$.each(data.list, function(index, data) {
}
markers.push( {
category:data.category,
id:data.id,
location:{
latitude:data.location.latitude,
longitude:data.location.longitude
}
});
});
});
return markers;
}
The first thing that strikes me is that every item will now be called "Object", while default, I'm still wondering if they can be labeled instead?
Further down the line, I try to access the id to compare it to a selection by the user,
but it doesn't work.
var selection = $(div_id).val();
var arr = $.inArray(selection, markersArray.id);
if( arr >= 0) {
return search(selection, div_id);
} else {
throw("selection not found in selectionSearch()");
}
What am I doing wrong here..?

To label the objects, add a toString function, like this:
markers.push({
toString: function () { return this.something; },
category:data.category,
id:data.id,
location:{
latitude:data.location.latitude,
longitude:data.location.longitude
}
});
To search the array, you'll need your own loop.
jQuery's $.inArray function searches the array for an exact match; it cannot be used to find an object with a matching property.
You can find a match yourself, like this:
for(var i = 0; i < markers.length; i++) {
if (markers[i].id === selection)
return search(selection, div_id);
}
throw("selection not found in selectionSearch()");

The type of each item is Object, there is nothing strange about that. There is no reason to try to change that.
To filter out items from an array based on a property in the item, you use the grep method:
var arr = $.grep(markers, function(e){ return e.id === selection; });
To check if the array is empty, you don't compare the array to a number, you use the length property:
if (arr.length > 0) {

Related

Delete value from array object in javascript (jquery)

I am trying to delete objects from my array via javascript. Im building a simple mobile jquery application and want to delete items from an array. I use the following code. I have a list with checkboxes in it. Every checkbox has a value that belongs to the list item. So when multiple checkboxes are checked.. it should delete all these objects (items) from the array.
function deleteFunction()
{
objects = getObjects();
$("input:checked").each(function()
{
var inputValue = $(this).val();
for(i = getObjects().length; i >=0; i--)
{
if('{"title":"'+ inputValue + '"}' == JSON.stringify(objects[i]))
{
objects.splice(i, 1);
return true;
}
}
});
alert(JSON.stringify(objects));
window.location.reload();
}
The annoying thing is as follows:
When i slice the object from the array, the object is restored on the second iteration. So it always removes only 1 object from the array.
To test my output i used the following code within the if statement:
alert(i);
alert(JSON.stringify(objects[i]));
objects.splice(i, 1);
alert(i);
alert(JSON.stringify(objects));
return true;
The output is as follows
1
{"title":"hi2"}
1
[{"title":"hi1"}, {"title":"hi3"}]
2
{"title":"hi3"}
2
[{"title":"hi1"}, {"title":"hi2"}]
so i slice hi2, but has returned
Thanx for answer and respond
Solution Thanx to depperm + indubitablee:
function deleteFunction()
{
var objects = getObjects();
$("input:checked").each(function()
{
var inputValue = $(this).val();
for(i = objects.length -1; i >=0; i--)
{
if(objects[i].title == inputValue)
{
objects.splice(i, 1);
}
}
});
localStorage.setItem("objects", JSON.stringify(objects));
window.location.reload();
}
There are a few things I would change, first in the for loop no need to call getObjects() each time just use objects. Then in the if simply check if the objects[i].title is the same as the inputValue.
function deleteFunction()
{
objects = getObjects();
$("input:checked").each(function()
{
var inputValue = $(this).val();
for(i = objects .length; i >=0; i--)
{
if(objects[i].title==inputValue)
{
objects.splice(i, 1);
}
}
});
alert(JSON.stringify(objects));
window.location.reload();
}
use .splice() instead of .slice().
slice does NOT alter/manipulate the original array at all, it just creates another array based on your selection.
splice does alter the original array.
reference: http://www.devcurry.com/2010/12/slice-and-splice-in-javascript.html
The array method slice does not remove array elements. Use splice instead.
There are some problems with your code:
You missed the keyword var sometimes.
The variable i is equal to the length of the array in the first iteration. It should be one minus that.
Instead of converting to JSON to compare the objects, you could have just compared the value of the title property.

how to filter on multiple keys with OR condition

According to the docs,
{name:"M", phone:"1"} predicate will return an array of items which have property name containing "M" and property phone containing "1".
I want to implement an or between those keys. for example it should return the rows which have property name containing "M" and also the rows having phone property containing "1".
Is there any expression by which I can do that? or I'll have to implement a custom filter for the same
you may try array filter method
list.filter(function(element){ return element.name.includes('M'); })
Can also try jquery
$.grep:
$.grep(list, function(element){ return element.name.includes('M'); })
Not sure if it's too early to conclude but it looks like creating a custom filter is the solution.
Here's it is,
.filter('orFilter', function () {
return function (list, filterOn) {
var out = [];
for (var i = 0; i < list.length; i += 1) {
var item = list[i];
for (var key in filterOn) {
var val = filterOn[key];
if (~item[key].indexOf(val)) {
out.push(item);
break;
}
}
}
return out;
}
});
I'll wait if someone posts a better solution.

How to search all levels nested Javascript object

I have a Javascript Object that represents a nested JSON string like this:
http://pastebin.com/vwZb1XrA
There are many levels that contain a "name" element. For example "SVI" or "Population" or "Human Development Index".
I am trying to find a way to iterate over every level of the object to find the name "SVI" or "Population" or "Human Development Index". When a match is made I want to then replace the weight value with something like this:
if (data[key].name == name) {
data[key].weight = 55;
}
You can recursively check each and every object, like this
function rec(currentObject, values, replacement) {
if (values.some(function(currentValue) {
return currentObject.name === currentValue;
})) {
currentObject.weight = replacement;
}
(currentObject.children || []).forEach(function(currentItem) {
rec(currentItem, values, replacement);
});
}
rec(data, ["SVI", "Population", "Human Development Index"], 55);
console.log(data);
Working demo
You could use a recursive function, so if you just want to update the first object with a certain name, something like this:
function search(name, value, object) {
if (object.name == name) {
object.weight = value;
return;
}
if(object.children) {
var i = object.children.length;
while(i--) {
search(name, value, object.children[i]);
}
}
}
This would update without returning anything. If you remove the return statement it should update all objects with the name you specify.
You need a recursive function, that will go through each element and process its children. Something like this might work:
function ChangeWeightsOfName(arr, nameVal) {
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
if (item.name === nameVal) {
item.weight = 42;
}
if (item.children && Array.isArray(item.children)) {
ChangeWeightsOfName(item.children, nameVal);
}
}
}
Your pasted JSON does not seem to be valid, so I included test one in this Fiddle

Filter a store with array of values from one property with ExtJS

I'm trying to apply a constraint on combobox. It's half-working at the moment.
On the combobox, I have this listener:
[...]
listeners: {
'focus': function (combo, value) {
var orgComboVal = Ext.getCmp('Org1')
var getOrgValue = orgComboVal.getValue();
if (typeof getOrgValue !== undefined) {
reseaulist.clearFilter(true);
for (var q = 0, l = getOrgValue.length; q < l; q++) {
reseaulist.filter([
{property:'code_organisme', value: getOrgValue[q]}
]);
}
}
}
}
Ext.getCmp('Org1') defines another combobox.
When orgComboVal.getValue() is a single value, the filter is well applying.
but when it's an array of value, eg ["5", "9"], it's not working and the combobox supposed to be filtered shows no value (so I guess a filter is still applied but in an incorrect way).
I guess it's because the reseaulist.filter is called multiple time.
How can I achieve this ?
I saw the filterBy method but I don't know how to make it work.
Also, this post is interesting : How to filter a store with multiple values at once? but same, can't make it work since
getOrgValue.split(',')
is showing an error
(Object Array has no method split)
Any tips ? I'm using ExtJS 4.2.
EDIT
Thanks to #rixo, I've made it.
Also, I had to change some of the code he provided me, because the value of the Org1 combobox was always an array, even if empty, so the store filter was never cleared.
Here it is :
'focus': function (combo, value) {
var orgComboVal = Ext.getCmp('Org1')
var values = orgComboVal.getValue();
console.log(values)
if (values != null) {
reseaulist.clearFilter(false);
if (Ext.isArray(values)) {
if (0 < values.length) {
reseaulist.filterBy(function(record, id) {
return Ext.Array.contains(values, record.get('code_organisme'));
});
} else {
reseaulist.clearFilter(true);
}
}
}
}
Each filter is applied one after the other on the previously filtered data set, so your code implements a logical AND. That's why all values are filtered out...
Here's an example using filterBy to accept any value that is in your array:
function (combo, value) {
var orgComboVal = Ext.getCmp('Org1')
var values = orgComboVal.getValue();
if (values != null) {
store.clearFilter(false);
if (Ext.isArray(values)) {
store.filterBy(function(record, id) {
return Ext.Array.contains(values, record.get('code_organisme'));
});
} else {
record.get('code_organisme') === values;
}
} else {
store.clearFilter(true);
}
}
Or you could also use a regex with the filter method:
function (combo, value) {
var orgComboVal = Ext.getCmp('Org1')
var values = orgComboVal.getValue();
if (values != null) {
var filterValue = Ext.isArray(values)
? new RegExp('^(?:' + Ext.Array.map(values, function(value){return Ext.escapeRe(value)}).join('|') + ')$')
: values;
store.clearFilter(false);
store.filter('code_organisme', filterValue);
} else {
store.clearFilter(true);
}
}
Concerning your error, arrays indeed don't have a split method. Strings can be split into an array. Arrays, on their side, can be joined into a string...
Try This....
var getOrgValue = "5,9,4"; // array of value
reseaulist.filterBy(function(rec, id) {
return getOrgValue.indexOf(rec.get('code_organisme')) !== -1;
});

How can I make these two index-locating filters into one generic one?

I have two filters, findEdited and getUnitIndex. They both do exactly the same thing (find the index of an element in an array), but in different parts of an array. I would like to combine them into one filter, getIndex.
Here's the first one:
myApp.filter('findEdited', function(){
return function(food, foods) {
for (var index in foods) {
if (foods[index].uid == food.uid) {
return index;
}
}
return -1;
}
});
In the controller:
var index = $filter('findEdited')(food, $scope.editedFood);
And the second one:
myApp.filter('getUnitIndex', function () {
return function(list, item) {
for( var i = 0; i < list.length; i++ ) {
if( list[i].gram == item.gram ) {
return(i);
}
}
return(-1);
}
});
Controller:
var unitIndex = $filter('getUnitIndex')(food.unit, $scope.editedFood[index].unit.selected);
As near as I can tell, the only functional difference between them is the .uid & .gram identifier, which is telling the loop which part of the object to match. I've tried to rewrite these into one filter, like this, with ref standing in for this identifier:
myApp.filter('findIndex', function () {
return function(list, item, ref) {
for( var i = 0; i < list.length; i++ ) {
if( list[i].ref == item.ref ) {
return(i);
}
}
return(-1);
}
});
And called like this, if I want ref to be uid:
var unitIndex = $filter('findIndex')(food.unit, $scope.editedFood[index].unit.selected, 'uid');
This doesn't work. The example above returns 0 on every run. Any suggestions on how to pass the desired reference to this filter so that I can use it generically to find the index of any array item in any array?
Plunkr
Update
I can't get this to work for the filter "findEdited". I have written my generic filter like this:
myApp.filter('getIndex', function(){
return function(list, item, ref) {
for (var index in list) {
if (list[index][ref] == item[ref]) {
return index;
}
}
return -1;
}
});
Which works if call it like this, to find the index of a food unit by matching 'gram':
var unitIndex = $filter('getIndex')(food.unit, $scope.editedFood[index].unit.selected, 'gram');
But it doesn't work if I call it like this, to find out if a food unit exists in the array editedFood:
var foodIndex = $filter('getIndex')(food, $scope.editedFood, 'uid');
I can see that I am passing in different search objects & search contexts, but the foodIndex search works if I pass it to the almost-identical filter findEdited filter above. Any ideas why?
Here's an updated Plunkr.
You must use the array-like notation here (you can use it for objects as well). item.ref would mean the property called ref, while item[ref] will mean the property called whatever the expression in the [] evaluates to (in this case, whatever is stored in the variable called ref).
if( list[i][ref] == item[ref] ) {
In other words, writing item.ref is equivalent to writing item['ref'].

Categories

Resources