In angular the use of Track by to track selection by value instead of by reference is a nice feature if needed. But lets say I switch the array behind and the selected object id matches a new Id I want the select to change as well
How do I force it to reevaluate?
HTML:
<select ng-options="option.id for option in collection track by option.id" ng-model="selectedObject"></select>
<button ng-click="updateCollection()">Update</button>
JS:
$scope.collection = [{
id: 1,
value: 0
}, {
id: 2,
value: 0
}, {
id: 3,
value: 0
}];
$scope.selectedObject = $scope.collection[0];
$scope.updateCollection = function () {
var newColl = [{
id: 1,
value: 100
}, {
id: 2,
value: 200
}, {
id: 3,
value: 300
}];
$scope.collection = newColl;
Lets say I pick Id 2 and then update the selectedObject is still the old id:2 value:0, I want it to change straight into id:2 value:200.
https://jsfiddle.net/IngoVals/p4ye3uaq/
P.S. Why doesn't the angular.copy work in the fiddle?
when you pick Id 2 then option model selectedObject is the second object of the collection which has Id of 2.
Then you press the update button and change $scope.collection at this point optoins will change in the select box, but the selected value is never changed, its still reference to the second object of the previous $scope.collection. so you need to update the selected value as well to do that,
get the selected object's index as,
var selectedIndex = $scope.collection.indexOf($scope.selectedObject);
assign the new collection as you did,
$scope.collection = newColl;
finally update the selectedObject based on that previously selected object's index.
$scope.selectedObject = $scope.collection[selectedIndex];
here is the DEMO
Related
I am using a dropdown that lists a data set.
I created a treeBoxValue variable to assign a predefined dropdown value. Thus, when I open the dropdown, the elements that contain the value of the variable treeBoxValue are checked.
My problem is that the presentation of these default values should contain the name and not the value.
Can someone help me to show only the names and not the values?
DEMO
Problem: The dropdown shows the values and not the name :(
When I open the dropdown, the values change to the name. I intend to get the names right at the beginning.
Note: If the dropdown did not open, refresh only the preview page.
Change this line:
treeBoxValue = ["1", "2"];
to this:
treeBoxValue = [1, 2];
In your Books array the field idBook is numeric.
Books = [
{
idBook: 1,
name: "name1"
},
{
idBook: 2,
name: "name2"
},
{
idBook: 3,
name: "name3"
}
];
I have this array of objects that i display on the UI table. It has 3 columns with name, contact and id.
[Object, Object, Object]
0:Object
name: "Rick"
Contact: "Yes"
id: 1
1:Object
name:"Anjie"
Contact:"No"
id: 2
2:Object
name:"dillan"
Contact:"Maybe"
id:3
Now, i add a new row to the top of table. So the newly added row into the array of objects, would look like this.
[Object, Object, Object,Object]
0:Object //newly added row. Since new row is added, it doesnt have any data.
name: ""
Contact: ""
id:
1:Object
name: "Rick"
Contact: "Yes"
id: 1
2:Object
name:"Anjie"
Contact:"No"
id: 2
3:Object
name:"dillan"
Contact:"Maybe"
id:3
I want the array of objects to look like this instead of above one.
[Object, Object, Object,Object]
0:Object //newly added row. Since new row is added, it doesnt have any data.
name: ""
Contact: ""
id: 4
1:Object
name: "Rick"
Contact: "Yes"
id: 1
2:Object
name:"Anjie"
Contact:"No"
id: 2
3:Object
name:"dillan"
Contact:"Maybe"
id:3
The only change is id value at 0th object. You can see i entered it as 4. It will check the max value in array of objects for id. In this case, it is 3. So it will increment by 1 and put it as the id value for newly added row.
Can someone let me know how to achieve this please.
Also, I had one more query.
If my id values are as follows.
1
2
3
4
5
6
And i delete 4 and 5. So new rows will be
1
2
5
6
Here, it will check max length as 4 and add id value of 5 to newly row. it will look somewhat like this.
5
1
2
5
6
In this case, 5 is repeated. I dont want this. I instead would like to see which is the highest value given to id, and then increment the id according to it. So it should look like this.
7
1
2
5
6
If I understand you correctly, you simply want to run:
array[0].id = array.length;
immediately after adding the row. Alternatively, if you can control the values of the object representing the new row when it is added, you could add the row as:
{
name:"",
Contact:"",
id: array.length + 1
}
EDIT:
In response to your edit, showing that rows of the array can be deleted.
In that case, to get the ID value, you have a number of options.
One is to go through all members of the array at time of deletion, and reduce the id of all rows which have an id greater than the deleted row. This is probably the best solution.
Example code:
var delete = function(array, idToDelete) {
for(var i = 0; i < array.length; i += 1) {
if(array[i].id === idToDelete) {
array.splice(i, 1);
} else if (array[i].id > idToDelete) {
array[i].id = array[i].id - 1;
}
}
}
If, for whatever reason, this is not an option, I would reccommend iterating through the array to find the highest ID in it, and adding 1.
var newId = array[0].id;
for(var i = 0; i < array.length; i += 1) {
if(array[i].id > newId) {
newId = array[i].id;
}
}
array.splice(0, 0, {name:"", Contact:"", id: newId + 1});
You can use this to find the next highest ID available (assuming that it's not trivially always equal to the length of the array):
var newID = 1 + myArray.reduce(function(p, c) {
return Math.max(c.id, p);
}, 0);
where myArray is your array.
In ES6 you could use:
var newID = 1 + myArray.reduce((p, c) => Math.max(c.id, p), 0)
If you only care about the ID being unique, you can add the timestamp as the ID
Lets assume that your array is called peopleContact
your code to add the item in the array of objects would look something like the following.
var person= new Object();
person.name= "";
person.Contact= "";
person.id = Date.now();
peopleContact.push(person);
I have an ng-repeat in a table. There are several of these tables inside a larger table. Each row has buttons for "add another" (which I have working) and remove current row/move row up-down (which I don't).
They are created with an array, each group in the table has its own array, with one member to start.
vm.choices1 = [{ id: 'choice1' }];
vm.choices2 = [{ id: 'choice1' }];
vm.choices3 = [{ id: 'choice1' }];
Clicking the plus button passes the current array and pushes a new item onto it, thus adding a repeater.
vm.addNewChoice = function(arr) {
var newItemNo = arr.length + 1;
arr.push({
'id': 'choice' + newItemNo
});
};
This works fine. Of course, now I have been asked to add the delete button and up/down buttons.
I get in concept what I need to do: I suppose somehow when the delete button is clicked I need to pass that index number to a delete function and pop that index from the array thats passed:
vm.deleteChoice = function(arr) {
arr.splice(index, index+1); //??
};
But I'm not sure how to get and pass the clicked index to the function. I used to know how to do this in jQuery, but not in Angular. If I can get the index of the clicked item into my function, I'm sure I can figure out the u/down buttons from there too.
Basic punker: http://plnkr.co/edit/WPdnmYbDSXC0LsbeMduM?p=preview
The directive ng-repeat creates a scope for every item that it iterates through. Part of the data assigned to this scope is the attribute $index which will be equal to the index in the array of the item/object.
Source: https://docs.angularjs.org/api/ng/directive/ngRepeat
I have a list with an observer function on it :
var names = ['joe', 'bob', 'loic'];
Object.observe(names, function(changes){
changes.forEach(function(change) {
console.log(change.type, change.name)
});
console.log("names",names);
});
console.log("######## del bob");
names.splice(1,1);// output is "update 1 - delete 2", why?
console.log("names", names) // but "bob" is the one deleted in the list
The deleted index according to the change object is 2, but I'm deleted the index 1, and the list has actually the index 1 deleted. Do you know why?
Is it because index 1 is updated to get index 2 value and index 2 is deleted?
Is there a way to get the actual deleted element index?
You can capture a splice event at the right index with Array.observe :
var names = ['joe', 'bob', 'loic'];
Array.observe(names, function(changes){
changes.forEach(function(change) {
console.log(change.type, change.name);
});
});
Thanks #xavier-delamotte :)
I have a list of JS objects defined by an integer ID.
objects = [{
id: 0,
type: 'null'
}, {
id: 1,
type: 'foo'
}, {
id: 2,
type: 'bar'
}];
I implemented a function to remove an element from my list :
removeObject = function(o){
objects.splice(objects.indexOf(o), 1);
}
My problem is that I need to create a function to add a new item in my list with a id not already used (for example the lower positive integer not present in the list).
I tried to do something like that but it did not work when I remove the object 0 (for example).
addObject = function(type){
objects.push({
id: objects.length,
type: type
});
};
How can I do this ?
EDIT 1
According to your answers, I assume that the best solution in term of performance is to just use a topId which is always incremented when I add a new object in my list.
But that do not answer to my requierement. Actually I think that #X-Pippes response could be good.
Should I do someting like that :
objects = [{
id: 0,
type: 'null'
}, {
id: 1,
type: 'foo'
}, {
id: 2,
type: 'bar'
}];
// Init available ids list with the default value
availableIds = [objects.length];
removeObject = function(o){
// Remove the object from the list
objects.splice(objects.indexOf(o), 1);
// Add its id to the available ids list
availableIds.push(o.id);
}
addObject = function(type){
// Get lower id available
var newId = Math.min.apply(Math,availableIds);
// Push the new object with the id retrieved
objects.push({
id: newId,
type: type
});
// Remove used id from the available ids list
availableIds.splice(availableIds.indexOf(newId), 1);
// Add a default id if available list is empty
if(availableIds.length < 1) availableIds.push(objects.length);
};
if you remove for instance 0 and the next addObject is 0 you have to do something like:
keep a list [initial empty] with every ID removed. When you need to add a new one, pick the shorter, add and delete from list.
Also keep a var with the biggest ID added. If the previous list is empty, add +1 to the var and addObject with that id
Use the correct structures. A JavaScript object will do the job. It guarantees that you only get one item for key, you can look up and remove by key in probably O(1)ish. No point trying to re-implement it in a less efficient manner, which will be O(n) lookup.
var structure = {
objects : {},
topId : 0
}
structure.add = function(item) {
var id = this.topId ++;
structure.objects[id] = item;
}
structure.add("thing")
structure.add("other thing")
structure.add("another thing")
structure.objects
>>> Object {0: "thing", 1: "other thing", 2: "another thing"}
structure.objects[1]
>> "other thing"
Then the normal index operations to get/set/delete.
If you use that function then you have an invariant (guarantee) on your data structure that you won't use the same ID twice.
You need a function to find the first free number:
addObject = function(type){
objects.push({
id: firstOpenIndex(),
type: type
});
};
firstOpenIndex = function() {
for(var idx = 0; true; i++) {
var found = false;
for(var o in objects) {
if (objects[o].id == idx) {
found = true;
break;
}
}
if (!found) return idx;
}
}
In Javascript MaxInt is 9007199254740992. Why not just keep incrementing?
You can and probably should just use an array(s) like:
objects.type=['null','foo','bar'];
to add an object see:
How to append something to an array?
to find a value: var index = objects.type.indexOf('foo');
to find 1st empty field var index = objects.type.indexOf(''); which you can use to find the element for adding (if index is -1 use objects.type.length) if you "delete" an element by setting it to "" or... unless you have specific reason for keeping the "ID" static (in this case the array index), remove the element and only append new ones to the end
to remove an element see:
How do I remove a particular element from an array in JavaScript?
which will allow you to just push/append the next data.
if you need a new object array with empty fields to fill because you get new data to track:
object.newField=new Array(objects.type.length);
If you get to this point where your object contains multiple arrays, you will probably want to create functions for insert/add and delete/remove, so you don't do an operation on 1 and not the other.
Everything is already built in (read likely already pretty fast) and you don't need to reinvent constructors for your really cool object type.