I am trying to create a select component wrapper in Angular 2 using ngModel. The events all fire off correctly once the selection is changed but I cannot set the initial selection when it's rendered.
This is my component:
#Component({
selector: 'my-dropdown',
inputs: ['selectedItem', 'items', 'label'],
outputs: ['selectedItemChange'],
template: `
<div class="field">
<label>{{label}}</label>
<select class="ui search selection dropdown" [ngModel]="selectedItem" (change)="onChange($event.target.value)">
<option value="" selected>Please Select</option>
<option *ngFor="#item of items" [value]="item.value">{{item.label}}</option>
</select>
</div>`
})
export class MyDropdownComponent {
items: DropdownValue[];
selectedItem: DropdownValue;
selectedItemChange: EventEmitter<any> = new EventEmitter();
private onChange(newValue) {
console.log(newValue);
this.selectedItem = this.items.find(item => item.value == newValue);
console.log(this.selectedItem);
this.selectedItemChange.emit(newValue);
}
}
And I'm using it in the view like this:
<my-dropdown [items]="selectItems" [(selectedItem)]="itemToSelect" [label]="'Please Select'"></my-dropdown>
When I set the itemToSelect value in the parent component on init, it does not set the selected option value in the UI.
I have also tried to use the ngModelChange event but it does not fire a change event.
itemToSelect is initially set to an object, so the input property of MyDropdownComponent is initially set to an object. But then in onChange() a string value is emit()ted, which then causes itemToSelect to be set to a string, and hence the input property becomes a string. Not good.
Just consistently use an object and it will work. Also, there is no need to assign this.selectedItem in onChange(), since the selected value will propagate back down from the parent (in general, you should never set input properties in the component – it also looks weird). You can also use ngModelChange now too:
<select class="ui search selection dropdown" [ngModel]="selectedItem.value"
(ngModelChange)="onChange($event)">
private onChange(newValue) {
console.log('nv',newValue);
selectedItem = this.items.find(item => item.value == newValue);
console.log('si',selectedItem);
this.selectedItemChange.emit(selectedItem);
}
}
Plunker
Note that I did not solve the issue of the user selecting "Please select". You'll need to add some logic to onChange() to handle that case.
When I set the itemToSelect value in the parent component on init, it does not set the selected option value in the UI.
Assuming you are using ngOnInit() in the parent, you should set value in one of the lifecycle hooks that are called later (because child doesn't yet exist in ngOnInit()), try ngAfterViewInit()...
Related
I have an element checkbox, that I want to reset the value of ng-model when another element is not showed, example: set to false if another element is not showed in my view. ng-show only hide my checkbox, but not reflect in object of controller.
<select ng-model="item.myOption" convert-to-boolean>
<option value="false" selected>Option false</option>
<option value="true">Option true</option>
</select>
<input type="checkbox" ng-model="item.myChecked" ng-show="item.myOption">
You can write small function on ng-change of select field, in which you can set model value of checkbox to either true or false or null.
app.controller('myCtrl', function($scope) {
$scope.item = {myOption: "true"}
$scope.myCheckbox = true;
$scope.changed = function() {
if($scope.item.myOption == "false") {
$scope.myCheckbox = false;
} else {
$scope.myCheckbox = true;
}
}
});
http://plnkr.co/edit/ekNxZImNIBisBCrfZsFS?p=preview
Similarly, you can change any dependent field's value (like finding age field value right after user selects his DOB using datepicker, etc). You can use switchcase either for large set of values instead of if else inside change function
I have a list of items coming in from an API and they won't always be the same, so the number of items in the array is always changing. I'm creating a checkbox for each item.
The user has the ability to check/uncheck each item. Here's what I want to do:
When an item is checked, it will push the ID of that item into an array
When an item is unchecked, it will remove the ID of that item from the array
I just need to know how I call something based on whether it was checked or unchecked. I've tried a "checked.delegate" and a "checked.trigger" and I can't seem to get that to work.
Just a regular click.delegate won't work because I can't keep state on whether it's true or false and I can't set variables for all of them because I don't always know which items are going to be coming in from the API. Any suggestions?
Try change.delegate or change.trigger like this:
VM method:
logchange(value) {
console.log(value);
}
View:
<input type="checkbox" change.delegate="logchange($event.target.checked)" />
There is (since when?) official documentation of how to solve exactly this specific problem cleanly: https://aurelia.io/docs/binding/checkboxes#array-of-numbers
No need to handle events!
Aurelia can bind directly to your array and handle everything for you - all you need to do is tell Aurelia what property of the elements you are repeating over to store in the array (the id).
The gist of it:
app.js
export class App {
products = [
{ id: 0, name: 'Motherboard' },
{ id: 1, name: 'CPU' },
{ id: 2, name: 'Memory' },
];
selectedProductIds = [];
}
app.html
<template>
<form>
<h4>Products</h4>
<label repeat.for="product of products">
<input type="checkbox" model.bind="product.id" checked.bind="selectedProductIds">
${product.id} - ${product.name}
</label>
<br>
Selected product IDs: ${selectedProductIds}
</form>
</template>
No other code is needed.
One way you can do this is with the help of a setter. Let's say you have a checkbox like this:
<input type="checkbox">
Create a private field in your View Model and then wrap it with a getter and a setter:
get isChecked(){
return this._isChecked;
}
set isChecked(value){
this._isChecked = value;
//enter your extra logic here, no need for an event handler
}
private _isChecked: boolean;
Then bind isChecked to the view:
<input type="checkbox" checked.bind="isChecked">
Every time the checkbox is checked or unchecked the setter will be called and you can call any method you want from within the setter.
Another more unconventional way to achieve this is by using the #bindable decorator like this:
#bindable isChecked: boolean;
It's unconventional because you probably don't want isChecked to be bindable but the decorator gives you access to the isCheckedChanged method:
isCheckedChanged(newValue, oldValue){
//Logic here
}
And of course there is the change event which you can catch with change.trigger and change.delegate but that has already been mentioned in another answer
Can somebody show me an example on how to bind ng-options to a getter and setter model, a plnker demo will be great.
Example on what i want to accomplish:
// As you can see the item is a object with two properties example:
// {Text: "hello", Value: 10}
setgetObject: function(value) {
if (angular.isDefined(value)) {
myObject = angular.copy(value); //copy the incoming object
}
return ????
}
<select class="form-control" name="rumFra" ng-model="getterSetter.setgetObject"
ng-options="item as item.Text for item in vm.configuration.Form.Room track by item.Value"
ng-model-options=" {getterSetter: true }">
Each time I make a new selection on my dropdown it will set the myObject with the new value but the dropdown is not effected even if I return the input element.
A working example on how to use Select tag with ng-options and ng-model-options="{setterGetter= "true"}" will be appreciated :-)
Look at Numyx's example:
http://plnkr.co/edit/SqJG8NP7e9NB9okcD4hN?p=preview
Because it is working but not with objects. Can somebody do it with objects?
Just use ng-model . ng-model binds the input,select and textareas.
see the example
<select ng-options="p.name for p in animal"
ng-model="selectedanimal"></select>
I have a dataset in angular where I add a default value as follows:
vm.serviceProperties.serviceCategories = clientcontext.clientlookup.serviceCategoryLookups();
vm.serviceProperties.serviceCategories.splice(0, 0, { 'serviceCategoryId': 0, 'serviceCategoryDisplayName': 'All' });
I need to bind this dataset to two select controls. For one, I need to show the 'All' value as default. For the other, I don't need the 'All' value at all.
How can I achieve that with the same dataset? I remember I saw somewhere that without defining the default value in the dataset itself, we can create an element option within the . Something like below:
<select>
<option> default</option>
<option ng-repeat="the dataset"></option>
</select>
But I'm not sure how to do it correct.
Create a property on the controllers that determines whether the default option is displayed or not.
Controller
app.controller('servicePropertiesWithDefault', function() {
$scope.showDefault = true;
});
app.controller('servicePropertiesWithoutDefault', function() {
$scope.showDefault = false;
});
Then in the template we use ng-if to show or hide the default option by passing in showDefault as the expression. Using ng-if is better than ng-show as it removes the element from the DOM.
Template
<select>
<option ng-if='showDefault'> default</option>
<option ng-repeat="the dataset"></option>
</select>
Working with angular, select2 widget.
I am declaring it in HTML something like this:
<div>
<select id = "dropdown"
...
<option value = "1" id="1">1</option>
<option value = "2" id="2" >2</option>
<option value = "3" id="3"" >3</option>
/select>
</div
and want to programatically change the selected item (called from another function).
When invoking the code:
$("#dropdown").select2().select2('val', "3")
I can see that the value at the dropdown changes, but when actually accessing the model attribute of the drop down (to fetch the selected item), it is not set to what I tried to set it to.
When checking the onChange event of the dropdown, I can see the e.val is undefined.
See the next fiddle as an example (after click the link, I wasn't suppose to get "undefined" in the alert box): http://jsfiddle.net/kcArV/1/
Any ideas what I am doing wrong ?
It should be
$('#attribute').select2().on('change', function(e) {
alert($(this).val());
});
e is the event object, not the select control, the method context this points to the select element, so you can call the .val() to get the selected value
Demo: Fiddle