AngularJS: refresh ng-options when property source object changes - angularjs

Full description:
I have list of options with multiple properties (not just key-value pair):
[
{
id: 1,
name: "111",
some: "qqq"
},
{
id: 2,
name: "222",
some: "www"
}
];
And select defined as:
<select name="mySelect" id="mySelect"
ng-options="option.name for option in opts track by option.id"
ng-model="mod1"></select>
Depending on app logic, extra property may change:
{
id: 2,
name: "222",
some: "www1"
}
But actual list in Select doesn't change!
However, if name changes, then entire optionList will be refreshed.
In short you can see demo on JSFiddle OR JSFiddle. I prepared 2 very similar examples:
When button is clicked only extra property updates
When button is clicked - both extra property and key receive new value
Does anybody know solution?
UPDATE
For now I'm solving that issue with update + delay + update solution:
this.click = function(){
$scope.opts = {};
$timeout(function() {
$scope.opts = { /* NEW OBJECT */};
}, 0);
}

OK, so I think I understand what you want, which is to be able to select an option whose nested values may have changed since the list was rendered in the DOM.
Based on that understanding, I believe that the plunker I have created illustrates a solution for you. If you select one of the options, and change the child value in the input field, two-way binding will update the model.
Basically, it is taking the users selection, and on select change, re-assigning the selected object to reference the original option in the options array. This will allow two-way binding to occur. If you view the code, you will see that the input fields are updating the option list itself ($scope.options), where-as the model that is being displayed is $scope.formData.model.
https://plnkr.co/edit/DLhI7t7XBw9EbIezBCjI?p=preview
HTML
<select
name="mySelect"
id="mySelect"
ng-model="formData.model"
ng-change="onChange(formData.model)"
ng-options="option.name for option in options track by option.id"></select>
SELECTED CHILD: {{formData.model.child.name}}
<hr>
<div ng-repeat="option in options">
Child Name for {{ option.name }}: <input ng-model="option.child.name">
</div>
JS
$scope.onChange = function(option) {
angular.forEach($scope.options,function(optionItem){
if (optionItem.id == option.id){
$scope.formData.model = optionItem;
}
})
}
$scope.options = [
{
id: 1,
name: "111",
child: {
id: 11,
name: "111-1"
}
},
{
id: 2,
name: "222",
child: {
id: 22,
name: "222-1"
}
}
];
$scope.formData = {
model: $scope.options[0]
};

Call $apply whenever you want to apply changes made.
$scope.$apply();
This will tell AngularJS to refresh.

Related

ng-options selected data return object

I have a array of object { id:x, name: 's' } and using ng-options to create drop down with default selected data. This is working fine so far.
Now when I select one of the option and see the selected data, it return complete object but i need only name field as well as default value must be selected on load.
// in controller
vm.teams = [
{
id: 1,
name:'First'
},
{
id: 2,
name:'Second'
},
{
id: 3,
name:'Third'
}
];
vm.teamFormData = {
team: ''
};
vm.getTeam = function(formData) {
$log.debug(formData); << here I get object
}
// in View
<select ng-init="vm.teamFormData.team = vm.teams[0]"
ng-model="vm.teamFormData.team"
ng-options="t.name for t in vm.teams track by t.id" >
</select>
Here is my working plunker
Your ngOptions syntax is slightly off - it's value as text for item in array
ng-options="t.name as t.name for t in vm.teams track by t.id"
And your ngInit then becomes
ng-init="vm.teamFormData.team = vm.teams[0].name"
Side note - you probably don't want ngInit - there's no real use case in your above example for it. Instead, just set the property in the controller.
See plunkr: https://plnkr.co/edit/7SGIdtfjucMnMqiEa7JY?p=preview

Angular 2 RC4 - Select ngModel delayed update

I'm trying to create a select control that will bind the value to an Object and on change I can get access to the selected object.
I know there has a been a lot of changes in the forms so not sure if this is a user error or bug or not possible.
Here is where I'm at so far: Link to Plunker
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: `
<h1>My First Angular 2 App</h1>
<select (change)="onChange($event)" [(ngModel)]="selected">
<option value=''></option>
<option *ngFor="let d of data" [ngValue]="d">
{{d.name}}
</option>
</select>
`
})
export class AppComponent {
diagnostic;
selected;
data = [
{ id: 1 , name: 'query 1', filters: [
{ 'filter1': 'material = 1'},
{'filter2': 'plant = 2'}
]
},
{ id: 2 , name: 'query 2', filters: [
{ 'filter1': 'material = 1'},
{'filter2': 'plant = 2'}
]
}
];
onChange(event) {
console.log(event.target.value);
console.log(this.selected);
}
}
What I would like to have happen is that when the onChange event is called that either I pass the Object value of the selected item into that method or get access to the selected value through the property bound in ngModel.
//expected
onChange(event) {
console.log(event.target.value) // selected object bound to ngValue
console.log(this.selected) // ngModel updated to object bound to selected option
}
But unfortunately, the event.target.value is a string version of the object and this.selected sort of works but is always behind on being updated.
Is there another way or proper way to handle this? Is the delay in the ngModel a bug?
Any help would be appreciated!
You should define select inputs/outputs as following:
<select [(ngModel)]="selected" (ngModelChange)="onChange()">
<option *ngFor="let d of data" [ngValue]="d">
{{d.name}}
</option>
</select>
and then the model is correctly applied to the property. http://plnkr.co/edit/JGgflTY9LvrDDhqqlSGP?p=preview
Notice that the definition of ngModel and ngModelChange should be ordered as is in example :)

How to run multiple successive select buttons in AngularJS

I facing an issue with having multiple selects in angularJS where each one of them is linked to the previous one and the value depended on the previous item selected which looks like could be done easily by angular but I am having a hard time figuring out how do I make the index of one select be passed to another select and at the same time making it unresponsive until some value is selected.
I also created a fiddle for the same for people to fiddle around with it.
Here is the concerned HTML
<div ng-app="myApp">
<div ng-controller="testController">
<select ng-model="carBrand" name="carBrand" required ng-options=" brand for brand in brands"></select>
<select ng-model="carModel" name="carModel" required ng-options="model.name for model in cars[0]"></select>
<!--I want the car brand(cars[0]) to be dynamic here. It should be prefreberably blacked out or uneditable until a Car brand is selected and once that particular brand is selected all the models pertaining to that brand only should be displayed in the ajoining select button-->
</div>
</div>
and an example app.js. Find the complete one at the fiddle
var app = angular.module('myApp', []);
app.controller("testController", function($scope) {
$scope.brands = ['Ford', 'Honda', 'Hyundai', 'Mahindra',
'Maruti Suzuki', 'Nissan', 'Renault', 'Skoda', 'Tata', 'Toyota', 'Volksvagen'
];
$scope.carBrand = $scope.brands[0];
$scope.cars = [];
/*These cars[0] and cars[1] are static declared but could well be called from a REST API endpoint in angular. For simplicity lets say they are already present. */
$scope.cars[0] = $scope.cars[0] = [{
name: "Figo",
capacity: 45
}, {
name: "Ecosport",
capacity: 52
}, {
name: "Fiesta",
capacity: 45
}, {
name: "Endeavour",
capacity: 71
}];
});
How do I solve the issue of getting an index from one select and passing it to the other to make this work and probably an additional perk would be to make it unresponsive in case no brand is selected.
Try ng-change:
<select ng-model="carBrand" name="carBrand" required ng-options=" brand for brand in brands"
ng-change="selectedCar(carBrand)"></select>
This returns the index of the selected brand:
$scope.selectedCar = function(brand) {
$scope.carIndex = $scope.brands.indexOf(brand);
};
Use it with the other dropdown as:
<select ng-model="carModel" name="carModel" required
ng-options="model.name for model in cars[carIndex]"></select>
Working Fiddle
When you select something from the first select, carBrand goes from undefined to the selected brand. You thus want the second select to be disabled if the carBrand is undefined (falsy):
<select ng-disabled="!carBrand" ...>
Then, you need to second select to contain the models associated to the selected brand (which is carBrand). So you need something like
<select ng-options="model.name for model in getModelsOfBrand(carBrand)" ...>
Now just implement this getModelsOfBrand(carBrand) function in the scope. It would be much easier if you had a better object model, like for example:
$scope.brands = [
{
name: 'Ford',
models: [
{
name: 'Figo',
capacity: 45
},
...
]
},
...
];
Then it would be as easy as
<select ng-options="model.name for model in carBrand.models" ...>

Kendo DropdownList and ng-model doesn't work

I have a Kendo Dropdownlist bound to an ObservableArray/DataSource. It duly fills the values from array. But when I bind ng-model to a property, the dropdownlist fails to select the value.
HTML:
<select kendo-drop-down-list k-options="dropOptions" ng-model="user.id"></select>
JS:
var users = [
{ id: 1, name: 'A' },
{ id: 2, name: 'B' },
{ id: 3, name: 'C' },
{ id: 4, name: 'D' },
{ id: 5, name: 'E' },
{ id: 6, name: 'F' }
];
var usersDataSource = new kendo.data.ObservableArray(users);
$scope.dropOptions = {
dataSource: usersDataSource,
dataTextField: 'name',
dataValueField: 'id',
optionLabel: "Select one..."
};
$scope.welcome = "World";
$scope.user = { id: 3 }
$scope.user = { id: 3 } should force dropdownlist to select C.
Here is link to Plunkr:
http://plnkr.co/edit/BxTqWet5sz725ZtKEKJr?p=preview
How can I for dropdownlist to make selection based on value assigned in property bound with ng-model. I have used k-ng-model as well, but it doesn't work. Please help me what am I doing wrong here. Thank you.
Edit: The selection in dropdownlist is not hardcoded. It will be fetched from database.
I was using Angular 1.4.9 with Kendo v2015.3.1111. Downgrading to Angular 1.4.8 made it work.
I got a solution that works.
<select kendo-drop-down-list
k-options="odsSoluciones"
k-data-text-field="'descripcion'"
k-data-value-field="'solucionId'"
k-value="prescDPIntercambio.solucionDPId"
ng-model="prescDPIntercambio.solucionDPId">
</select>
$scope.odsSoluciones =
dataSource: new kendo.data.DataSource({
data: solucionesModel.data,
}),
};
In my case odsSoluciones returns an array with "solucionId" and "descripcion" fields and prescDPIntercambio.solucionDPId is the value I want to see selected
Kendo dropdown value does not reflect selection based on ng-model. Instead it provides a new attribute : k-ng-model
For a basic example, have a look at this: k-ng-model
Just add k-value = "user.id"to the template.
Working Plunker
<div ng-controller="AppCtrl">
<h1>Hello {{ welcome }}!</h1>
<div>Selected value is {{ user.id }}</div>
<select kendo-drop-down-list
k-options="dropOptions"
ng-model="user.id"
value= 3
class="glow"></select>
</div>
There is a wierd situation where when I declare the ng-model as an object for example $scope.abc.xyz = "test" ,the bind works whereas if I do $scope.abc = "test" , the bind does not work.
Not sure what the issue is :)

How to set a custom object value in angular ng-options?

I have a array opts with the different options for a <select> element. Array's objects have a property text for display and a property value for get the value and set in a variable $scope.opt2.
Controller:
function MyCtrl($scope) {
$scope.opts = [
{value: 10, text: '1st' },
{value: 20, text: '2nd' }
];
}
I want set:
$scope.opt2 = {ref: 10} and show 1st when the first option is selected
$scope.opt2 = {ref: 20} and show 2nd when the second option is selected
I tried:
<select ng-model="opt2" ng-options="{ref: obj.value} as obj.text for obj in opts">
The value sets correctly but the text is not show. Any solution?
Examples for testing: http://codepen.io/ces/pen/azbLzX
While Philipps response will work, it's a little more complicated then you need it to be, change your select to this:
<select ng-model="opt2.ref" ng-options="obj.value as obj.text for obj in opts">
See the edited codepen here: http://codepen.io/anon/pen/XJWeVQ

Resources