I have a vue-select multiselect (http://sagalbot.github.io/vue-select/) defined as
<v-Select label="label" multiple :on-change="updateCities" :options="cities"></v-Select>
The method updateCities is defined as
'updateCities': function (menuItem) {
var name = ''
// iterate thru the elements in the multiselect
menuItem.forEach(function (elem, i) {
name = elem.label
return name
})
// push the selected element to an array in the data model
this.state.city.push(name)
}
and the data model is defined as
'data' () {
return {
'state': {
'city': []
}
}
}
When I click on the multiselect and choose a city, both the menu and the data model array city is updated correctly but when I click on the X on the top right of the menu item to remove the element from menu and from the data model array city. as shown below
The element is correctly removed from the menu but not from the data model array city.
How do I fix this?
This was resolved by assigning the value of this.state.city to the menu item as:
'updateAdvertisers': function (menuItem) {
this.state.city= menuItem.map(elem => elem.label)
}
Related
context: Angular applications using the ngx-select-dropdown. A user can select multiple values, these values get sorted into "buckets" and sent to the api.
Issue: I am unable to remove a selected item from the end array - this.filterState. I have added a check to ensure that an item cant be added more than once - a click to select the item and a click to deselect the item. I thought that this would be a good time to remove the item with a splice as the user would have clicked to deselect if it already exists in the array - however, the dropdown does not pass the value of a deselected object it just removes it from the value array of the dropdown.
const index = this.filterState[convertedParam].indexOf(value);
if (index === -1) {
this.filterState[convertedParam].push(value);
}
Proposed solution: I think it will need some sort of comparison upon event change against the dropdown value object and the array that was previously sent to the api.
End goal: To be able to add and remove objects from the sorted array
Here is a stackblitz that I put together...
app.component.ts
handleFilterChange(prop: string, value: any): void {
// I think the comparison with "value" and whats already in "this.filterState" will need to be done here?
let field = this.fields.find(f => f.name === prop);
if (field.params) {
value.forEach(v => this.setFilterState(v.type, v, field));
} else {
this.setFilterState(prop, value, field);
}
console.log("SUBMITTED SORTED VALUES", this.filterState);
}
setFilterState(prop: string, value: any, field: Field): void {
const colourParamMap = {
I_am_RED: "reds",
I_am_BLUE: "blues",
I_am_GREEN: "greens"
};
if (field.name === "multiselect_1") {
const convertedParam = colourParamMap[prop];
const index = this.filterState[convertedParam].indexOf(value);
//stops from adding same value again and adds value to array
if (index === -1) {
this.filterState[convertedParam].push(value);
}
} else {
//There will be more logic here
this.filterState[prop] = value;
}
}
https://stackblitz.com/edit/ngx-select-dropdown-xkfbyr?file=app%2Fapp.component.ts
A simple fix in the end - I was trying to over complicate things. I needed to reset the this.filterState as the value from the dropdown will include every value from before, minus the ones that were deselected.
handleFilterChange(prop: string, value: any): void {
this.filterState = {
reds: [],
blues: [],
greens: []
};
I have an ng-repeat displaying items from json, based on what the user enters into a field it can be filtered.
<tr ng-repeat="i in filteredItems = (iso3166 | filter: {alpha_2: isoQuery})">
this all works as expected.
Each item in the group ("iso3166") has 3 boolean values, "restricted", "unrestricted", and "unclassified", for each of the columns "license", "prohibited", and "size".
The user can set one of these values in each column in each row to true or false:
This works fine.
What I need to add is an "ALL" row at the top that will set every item in the filtered set to whichever button was clicked in each column.
In other words, if the user clicks the ALL rows "restricted" button in the "license" column, every row's "license" "restricted" value should be toggled to true or false. I'm not sure of the syntax to set the value.
Now I have the ng-click as
ng-click="setAll('col1','licensed')"
and the function as
$scope.setAll = function (column, value) {
angular.forEach($scope.filteredItems, function (value, key) {
??
});
};
How do I assign the correct value to each row in the loop?
At the moment your inner function shadows the value variable. Rename the local variable to something else in order to change it.
$scope.setAll = function (column, value) {
angular.forEach($scope.filteredItems, function (item, key) {
item[column] = value;
});
};
I want to add a comboBox or menu button to my interface which will have data in it that comes from an array. The data in the array won't always be the same so I need the button to be "dynamic". How can I achieve that ? I can't specify a model if the array changes...
Edit: I'm using ExtJS 6, so I need to be able to feed the menu parameter:
menu: [{
text:'Menu Item 1'
},{
text:'Menu Item 2'
},{
text:'Menu Item 3'
}]
Example:
1) Users selects a menu item and click on a send button.
2) Depending on the value of the item the user clicked on, a javascript array is created with sometimes 2, sometimes 10 fields in it.
3) The fields are shown in a new menu button or combobox.
Thanks for your help !
HTML
<input type="text" name="example" list="exampleList">
<datalist id="exampleList">
<option value="A">A</option>
<option value="B">B</option>
</datalist>
Javascript
function generateOptionsFromDynamicArray (arr) {
// Get the datalist by id, cache option variable
var datalist = document.querySelector('#exampleList'),
option;
// Remove old options
while( datalist.firstChild ) {
datalist.removeChild(datalist.firstChild);
}
// Loop through array
for (var i = 0, l = arr.length; i < l; ++i) {
option = document.createElement('option');
option.setAttribute('value', arr[i]);
option.innerText = arr[i];
datalist.appendChild(option);
}
}
I created a function that you can pass that dynamic array into in order to update the combobox, in this case I'm using a datalist.
A few points about this code, you should add a check to ensure arr is an array or "array-like" (typedarrays I'm looking at you). You should also remove the datalist from the DOM while these changes are happening so you dont redraw the DOM on each iteration
I've created a fiddle for testing.
You cannot listen to an array change event, so whenever you change the array, you would also have to call following function:
function arrayToStore(array) {
var store = Ext.getCmp("myComboId").getStore();
//var store = Ext.getStore("myComboStore");
store.removeAll();
store.add(array.map(function(item) {
// This maps the array entry into a model you can add to the store.
// Instead of "field1", use your field name.
// If your array contains an object, you can preprocess it here.
// "field1" would be the default value if you have defined
// an implicit store by providing an array in the combo config:
// store:['item1','item2','item3'],
return {
field1:item
};
});
}
I want to update SpaceBars #index native helper when I sort the items displayed within an #each iteration. I guess that the correct way to do it is to sort the cursor I use in the #each.
The cursor comes from an Items collection. The array that I use to sort them belongs to another collection document (Projects), and it stores an ordered list of each published item id.
After I drop an item at its new position, I update each item index in the project document array using the sortable stop function. To do so, I $pull it out first, and then $push it at a specific position.
stop: function(e, ui) {
var project = Projects.findOne();
// get the dragged html element and the one before and after it
el = ui.item.get(0)
before = ui.item.prev().get(0)
after = ui.item.next().get(0)
console.log(Blaze.getData(el)._id); //gets the id of the item dropped
if(!before) {
//if it was dragged into the first position
console.log(after.dataset.index); //gets the index of the next element
Projects.update({_id: project._id},
{$pull:
{
items:Blaze.getData(el)._id
}
})
Projects.update({_id: project._id},
{$push:
{
items:
{
$each:[Blaze.getData(el)._id],
$position:0
}
}
})
} else if(!after) {
//if it was dragged into the last position
Projects.update({_id: project._id},
{$pull:
{
items:Blaze.getData(el)._id
}
})
Projects.update({_id: project._id},
{$push:
{
items: Blaze.getData(el)._id
}
})
} else
Projects.update({_id: project._id},
{$pull:
{
items:Blaze.getData(el)._id
}
})
Projects.update({_id: project._id},
{$push:
{
items:
{
$each:[Blaze.getData(el)._id],
$position:after.dataset.index -1
}
}
})
}
As you might see, I use the index property of my item in the above function (e.g. $position:after.dataset.index -1). This is what I want to update by sorting my cursor.
To summarize it, on one hand, I have an ordered (using index) array of ids; Example:
items : {
Id2131,
Id4233,
Id2243,
Id2331,
Id2455,
Id2123
}
and on the other hand, I have a publication with all the ids matching the array, but not in the right order.
How can I sort my cursor Items.find() following the order of my other document array?
I just realized how to do it. Here is how I proceeded.
The helper feeding my #each iteration does not return simple Items.find() anymore but a sorted array version of it made with an dedicated function. It now returns sortItems(Items.find())
And the sortItems function looks like this:
var sortItems= function(cursor) {
if(!cursor) {
return [];
}
var raw = cursor.fetch();
var project = Projects.findOne()
var sorted = [];
_.each( project.items, function(id){
_.each( raw, function(item){
if (item._id === id) {
sorted.push(item);
}
})
})
return sorted;
};
I have a Knockout.JS observable array that is the basis for a list:
self.list_elements = ko.observableArray([
new list_element("0001", "product 1", "3.99")
]);
Variables in this array are observables:
function list_element ( id, name, price ) {
this.item_id = ko.observable(id);
this.item_name = ko.observable(name);
this.item_price = ko.observable(price);
}
There is also a details view, which I want to fill with the data of a list element that is clicked, e.g:
<span data-bind="text: an_item_id"></span>
The function to fill this gets the respective array item from the click handler.
self.fill_form = function ( array_item ) {
// array_item is the array element corresponding to the selected list element
}
How can I connect the details view with the values in the array so that changing the value in the array shows up in the details view?
Normally, you would create a selected observable and populate it with the currently selected item. Then, you would use the with to render a section with a context specific to the selected item.
Something like:
var ViewModel = function() {
var self = this;
this.list_elements = ko.observableArray([...]);
this.selected = ko.observable();
this.fill_form = function(item) {
self.selected(item);
};
};
Then, you would bind a section like:
<div data-bind="with: selected">
...
</div>
If you don't need to perform any logic in your fill_form function, then you can even just bind a click directly against your selected observable, as the item will get passed as the first argument to the observable (which is a function) and to set its value.
Here is a sample example: http://jsfiddle.net/rniemeyer/YPKk2/