I want to make my page a little lighter weight. I have some elements that have to be select options but I need them to load just as the user touches the control. Maybe display a loading dialog for a split second to give them feedback. How can I do this in Angular? I tried ng-click and ng-focus to trigger the model option population but it never fires.
<select name="Category" ng-model="selectedCategory" ng-options="item.name as item.name for item in categories">
<option value="" disabled selected>All Categories</option>
</select>
ng-focus should work. Just let $scope.categories start out as an empty array, and populate it in your ng-focus function:
$scope.categories = [];
$scope.selectedCategory = {};
$scope.loadOptions = function() {
if ($scope.categories.length == 0) {
$scope.categories = [{
name: 'option1'
}, {
name: 'option2'
}, {
name: 'option3'
}];
}
}
HTML:
<select name="Category" ng-model="selectedCategory"
ng-options="item.name as item.name for item in categories"
ng-focus="loadOptions()">
Plunker
Related
I am using Angularjs with select2. I have a multiselect box that gets populated based off the values selected in another dropdown. I use an click event on a button for fire a method that adds a list of ids to the ngModel object assigned to the multiselect box. I can see the values getting added properly after I trigger a change event on that form element because even after reading articles and changing the ngModel value to be a object and not an array, the values still aren't binding when I add them programmatically. After I trigger the change event on the form element, I am able to see some of the values but not all of them. Some of the values were removed. Below is my code.
addRecord.vm
<div class="col-sm-4">
<select ui-select2="{ allowClear: false, minimumResultsForSearch: 10, theme: bootstrap }"
name="recordTemplate" ng-model="addRecordCtrl.selectedTemplate">
<option class="selectPlaceholder" value="" disabled selected hidden>- Chose Record Template -</option>
<option ng-repeat="template in addRecordCtrl.recordTemplates" value="{{record.name}}">{{record.name}}</option>
</select>
</div>
<div class="col-sm-9">
<button id="addButton" class="btn btn-primary btn-lg" ng-click="addRecordCtrl.addRecords()" ng-disabled="addRecordCtrl.isLoading
|| addRecordCtrl.isEdit">Add</button>
</div>
<div class="col-lg-9 col-xs-9" id="recordContainer" name="recordContainer">
<select ui-select2="{ allowClear: false, minimumResultsForSearch: Infinity}"
name="records" id="records" class="medium"
multiple ng-model="addRecordCtrl.records.id"
ng-required="true" ng-cloak>
<option ng-repeat="record in addRecordCtrl.availableRecords | notInArray:addRecordCtrl.selectedRecordIds.ids:'recordId'"
value="{{record.recordId}}">{{record.name}}</option>
</select>
<input type="hidden" ng-model="addRecordCtrl.selectedRecordName" value="">
</div>
app.js
recordApp.controller('RecordController', ['$http', '$window', '$modal', '$log','$filter', '$timeout', function ($http, $window, $modal, $log, $filter, $timeout) {
var self = this;
self.availableRecords = [{
recordId: "1",
name: "Love and Happiness"
},{
recordId: "2",
name: "Feel the Burn"
},{
recordId: "3",
name: "Juicy Baby"
}];
self.recordTemplates = null;
self.selectedRecordIds = {};
self.addRecords = function () {
//add record ids from the selected records.
self.recordTemplates.recordId.forEach(function (id) {
self.selectedRecordIds.ids.push(id.recordId);
});
self.recordAdded = true;
};
}]);
//filter to filter out ids that have already been selected.
recordsApp.filter('notInArray', ['$filter', function($filter){
return function(list, arrayFilter, element){
if(arrayFilter){
return $filter("filter")(list, function(listItem){
for (var i = 0; i < arrayFilter.length; i++) {
if (arrayFilter[i][element] == listItem[element])
return false;
}
return true;
});
}
};
}]);
The reason some of my values were getting deleted from the selectedRecordIds array after adding them programmatically was because they are not in the availableRecords array. Once I made sure those values where in the availableRecords array all was well.
I have angularjs dropdown list box:
<select class="form-control"
ng-model="editor.frequency"
ng-options="item as item.Name for item in editor.frequencies"
ng-change="editor.editFrequencyManual = false;">
</select>
After user click on option in dropdown list box I need to get clicked(selected) value and the old value(before selection).
Any idea how can I get this two values?Is there event function that I sholud use?
You could watch the changes on your model:
$scope.$watch('editor', function(newValue, oldValue){
//
});
Or you could modify ng-change so that it passes old and new values as parameters:
<select class="form-control"
ng-model="editor.frequency"
ng-options="item as item.Name for item in editor.frequencies"
ng-change="changed(editor.frequency, {{editor.frequency}}); editor.editFrequencyManual = false;">
</select>
Of course, you should move editor.editFrequencyManual = false; into the change function.
function myController($scope) {
$scope.myModel = {};
$scope.doThis = function(newValue, oldValue) {
console.log("New value: " + newValue);
console.log("Old value: " + oldValue);
}
}
angular.module('myApp', []);
angular
.module('myApp')
.controller('myController', myController);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myController">
<select ng-model="myModel" ng-change="doThis(myModel, '{{myModel}}');">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
</div>
</div>
I'm trying to get these dynamic filters working and its almost there I think. Looks like the model isn't being passed back to the watch function. I would've expected it to work with the first set of filters at least but it doesn't.
What I'm trying to achieve is that when the user selects an option from the select list and sets a value in the input box the data is filtered. The user can optionally add another set of filters by clicking the "add fields" button. If there user completes the second set of filters then the data is filtered further.
This is what I've got so far. If there's only one filter showing then shouldn't it just work?
This is the code that creates the user defined filters.
<div data-ng-repeat="filter in filters">
<select ng-model="filter.id">
<option value="age">Age</option>
<option value="customerId">CustomerID</option>
<option value="productId">ProductID</option>
<option value="name">Name</option>
</select>
<input type="text" ng-model="data.search[filter.id]">
<button class="remove" ng-show="$last" ng-click="removeFilter()">-</button>
Add fields
I think I'm almost there, got a better understanding of hierarchical scope. I've referred to a few tutorial and examples but I'm not quite there yet. I think my issue with this is that I'm not communicating the models properly. Still a little bit lost with this. Any further tips/suggestions would be great. I'm wondering if I should move some of he code from the controller in my directive into the resultsCtrl controller. Really not sure.
This fiddle gave me the idea to use filter.id within my template ng-repeat
This plnkr was helpful.
I'm getting somewhere now. This plnkr shows it working, the last thing I want to do with it is when you remove a filter it automatically updates the search object to remove the relevant filter.
Any suggestions on how to do this?
You are breaking the golden rule of "always have a dot in ng-model".
Why? because objects have inheritance and primitives do not.
ng-model="filterType"
is being defined inside a child scope created by ng-repeat. Because it is a primitive the parent scope in controller can not see it. However if it was a property of an object that was available at parent level, the reference would be shared between parent and child.
Once you fix that bug you will run into a bug where scope.search is not an object either so your $watch function will throw an exception also. In main controller can set:
$scope.search ={};
Do some reading up on how hierarchical scopes work in angular. There is plenty to be found in web searches and angular docs
I eventually got this solved :)
directive:
angular.module('dynamicFiltersDirective', [])
.directive('dynamicFilters', function() {
return {
restrict: 'AE',
scope: {
filtersArray: '=',
searchObject: '='
},
link: function(scope) {
scope.addFilter = function() {
var newItemNo = scope.filtersArray.length+1;
scope.filtersArray.push({'id':'filter'+newItemNo});
};
scope.removeFilter = function(option) {
var lastItem = scope.filtersArray.length-1;
scope.filtersArray.splice(lastItem);
delete scope.searchObject[option];
};
scope.updateFilters = function (model) {
scope.searchObject[model];
}
},
templateUrl: 'filtertemplate.html'
}
});
controller:
angular.module('app', ['dynamicFiltersDirective']).controller('resultsCtrl', function($scope){
$scope.filters = [{id: 'filter1'}];
$scope.search = {};
$scope.persons = [{
name: 'Jim',
age: 21,
customerId: 1,
productId: 4
},{
name: 'Frank',
age: 20,
customerId: 2,
productId: 4
},{
name: 'Bob',
age: 20,
customerId: 3,
productId: 5
},{
name: 'Bill',
age: 20,
customerId: 3,
productId: 5
}];
});
template:
<div data-ng-repeat="filter in filtersArray">
<select ng-model="filter.id">
<option value="age">Age</option>
<option value="customerId">CustomerID</option>
<option value="productId">ProductID</option>
<option value="name">Name</option>
</select>
<input type="text" ng-model="searchObject[filter.id]" ng-change="updateFilters(searchObject[filter.id])">
<button class="remove" ng-show="$last" ng-click="removeFilter(filter.id)">-</button>
</div>
<button class="addfields" ng-click="addFilter()">Add fields</button>
<div id="filtersDisplay">
{{ filters }}
</div>
index.html
<div ng-controller="resultsCtrl">
<dynamic-filters filters-array="filters" search-object="search"> </dynamic-filters>
<div ng-repeat="person in persons | filter: search">
{{person.name}}
</div>
Here's my example plnkr
Is there any way to bind textbox to select list without $Watch .
the Plunker
i don't want to let user type everything and bind to selectlist .
Thanks
So if you need to make a select and to display the result in your input without $scope.$watch just use the attribut disabled on the input. Try this :
<input type="text" ng-model="text.name" disabled/>
<select ng-model="text" ng-options="option.name for option in options">
</select>
In your controller :
app.controller('MainCtrl', function($scope) {
$scope.options = [{
name: 'a',
value: 'something-cool-value'
}, {
name: 'b',
value: 'something-else-value'
}];
You can try in your plunker this is working. Hope this helped.
This is my angular html file code. In my mongo database frequencyType added as frequencyType = "1", but I want frequencyType = NumberInt(1);
<div class="span4">
<select class="span12 combobox" ng-model="frequencyType" required>
<option value="1">Daily</option>
<option value="2">Weekly</option>
<option value="3">Monthly</option>
<option value="4">Yearly</option>
</select>
</div>
I get in my database frequencyType = "1" but I want frequencyType = NumberInt(1).
There is an easier way:
Just use value*1 as your id, that will convert the string to int without changing the value... assuming the id is an integer.
so the result is>
<div ng-app ng-controller="MyCtrl">
<select ng-model="selectedItem" ng-options="selectedItem*1 as selectedItem for selectedItem in values"></select>
selectedItem: {{selectedItem}}
</div>
This will work in more cases, since indexOf is not available in objects, only in arrays. This solution works for objects with integers as keys (for example if some keys are missing, or if you use db ids)
Most solutions discussed here require using the ngOptions directive instead of using static <option> elements in the HTML code, as was the case in the OP's code.
Angular 1.6.x
Edit If you use Angular 1.6.x, just use the ng-value directive and it will work as expected.
angular.module('nonStringSelect', [])
.run(function($rootScope) {
$rootScope.model = { id: 2 };
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<div ng-app="nonStringSelect">
<select ng-model="model.id">
<option ng-value="0">Zero</option>
<option ng-value="1">One</option>
<option ng-value="2">Two</option>
</select>
{{ model }}
</div>
Older versions
There is a way to make it work while still using static elements. It's shown in the AngularJS select directive documentation.
The idea is to use a directive to register a parser and a formatter on the model. The parser will do the string-to-int conversion when the item is selected, while the formatter will do the int-to-string conversion when the model changes.
Code below (taken directly from the AngularJS documentation page, credit not mine).
https://code.angularjs.org/1.4.6/docs/api/ng/directive/select#binding-select-to-a-non-string-value-via-ngmodel-parsing-formatting
angular.module('nonStringSelect', [])
.run(function($rootScope) {
$rootScope.model = { id: 2 };
})
.directive('convertToNumber', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$parsers.push(function(val) {
return parseInt(val, 10);
});
ngModel.$formatters.push(function(val) {
return '' + val;
});
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="nonStringSelect">
<select ng-model="model.id" convert-to-number>
<option value="0">Zero</option>
<option value="1">One</option>
<option value="2">Two</option>
</select>
{{ model }}
</div>
I've just had the same problem and figured out the right way to do this - no 'magic' required. :)
function MyCtrl($scope) {
$scope.values = [
{name : "Daily", id : 1},
{name : "Weekly", id : 2},
{name : "Monthly", id : 3},
{name : "Yearly", id : 4}];
$scope.selectedItem = $scope.values[0].id;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<div ng-app ng-controller="MyCtrl">
<select ng-model="selectedItem" ng-options="selectedItem.id as selectedItem.name for selectedItem in values"></select>
selectedItem: {{selectedItem}}
</div>
I think the angular way to do this is to use the directive "convert-to-number" in the select tag.
<select class="span12 combobox" ng-model="frequencyType" required convert-to-number>
<option value="1">Daily</option>
<option value="2">Weekly</option>
<option value="3">Monthly</option>
<option value="4">Yearly</option>
</select>
You can see the documentation and a fiddle here at the end of the page : https://docs.angularjs.org/api/ng/directive/select
I suggest you to try to use indexOf.
JS
function MyCtrl($scope) {
$scope.values = ["Daily","Weekly","Monthly","Yearly"];
$scope.selectedItem = 0;
}
HTML
<div ng-app ng-controller="MyCtrl">
<select ng-model="selectedItem" ng-options="values.indexOf(selectedItem) as selectedItem for selectedItem in values"></select>
selectedItem: {{selectedItem}}
</div>
Demo Fiddle
So send to mongoDB $scope.selectedItem value
This is the easiest way I have found so far:
function Controller($scope) {
$scope.options = {
"First option" : 1,
"Second option" : 2,
"Last option" : 10
}
$scope.myoption = 2;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="Controller">
<select ng-model="myoption" ng-options="label for (label, value) in options"></select>
Option Selected: {{myoption}}
</div>
Or, if you want to use numeric indexes:
function Controller($scope) {
$scope.options = {
1 : "First option",
2 : "Second option",
10 : "Last option"
}
$scope.myoption = 2;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="Controller">
<select ng-model="myoption" ng-options="value*1 as label for (value, label) in options"></select>
Option Selected: {{myoption}}
</div>
For Angular 2, follow the rabit...