I'm trying to implement the classic Country > State > City combobox using angular directives.
I'm willing to link them by a custom attribute pair name/depends-on, but I don't know if there's a better form.
My HTML is the following:
<div ng-app="app" ng-controller="Ctrl">
<multiselect source-url="/countries.json" auto-init="true" name="Contries">
<select multiple ng-model="$parent.selectedOptions" ng-change="$parent.handleChange()">
<optgroup ng-repeat="(continent, countries) in $parent.optionList" label="{{continent}}">
<option ng-repeat="country in countries" value="{{country.code}}">
{{country.code}} - {{country.name}}
</option>
</optgroup>
</select>
</multiselect>
<multiselect source-url="/states.json" depends-on="Countries" name="States">
<select multiple ng-model="$parent.selectedOptions" ng-change="$parent.handleChange()">
<optgroup ng-repeat="(continent, countries) in $parent.optionList" label="{{continent}}">
<option ng-repeat="country in countries" value="{{country.code}}"> {{country.code}} - {{country.name}}
</option>
</optgroup>
</select>
</multiselect>
</div>
The Javascript:
app.directive('multiselect', function () {
return {
restrict: 'E',
transclude: true,
scope: {
sourceUrl : '#',
autoInit : '#',
dependsOn : '#'
},
controller: ['$scope', '$element', '$attrs', '$transclude', '$http', function ($scope, $element, $attrs, $transclude, $http) {
$scope.handleChange = function handleChange() {
console.log($scope.selectedOptions)
}
console.log($scope.dependsOn)
function updateSource() {
const config = {
params : {}
}
if ($scope.dependsOn) {
// how do I get dependsOnValue?????
config.params[$scope.dependsOn.toLowerCase()] = $scope.dependsOnValue
}
$http.get($scope.sourceUrl, config)
.then(function (response) {
$scope.optionList = response.data
})
}
if ($scope.autoInit) {
updateSource()
}
}],
template: '<ng-transclude></ng-transclude>'
}
})
The question is: how do I watch for changes in Countries in order to get its value to update States?
I'm trying to make this as reusable as possible.
Related
I use select2, $localStorage and angularjs in my project, I want to get the value of my $localstorage as a default value but when I try this
$('.select').val($localStorage.f.tab.idSelect).trigger('change');
it doesn't work it doesn't show my default value I have the same issue for my select multiple
$('.selectSec').val($localStorage.f.tab.selectSecArray).trigger('change');
this is my .aspx file
<select class="form-control select">
<option value="">---Please select---</option>
<option ng-repeat="option in test" value="{{option.testid}}">{{option.testname}}</option>
</select>
<select class="form-control selectSec" name="secs[]" multiple="multiple">
<option value="">---Please select---</option>
<option ng-repeat="option in secs" value="{{option.secid}}">{{option.secname}}</option>
</select>
this is my app.js
app.controller('AppCtrl', function ($scope, $http, $localStorage) {
$http.get("url1").then(function (response) {
$scope.test= response.data.Liste
})
$http.get("url2").then(function (response) {
$scope.secs= response.data.Liste
})
$('.select').val($localStorage.f.tab.idSelect).trigger('change');
$('.selectSec').val($localStorage.f.tab.selectSecArray).trigger('change');
jQuery(".select").change(function (e) {
if (e.target.value == "")
console.log("null")
else
$localStorage.f.tab.idSelect = e.target.value
}) // I do the same for the multiple select
})
When do that it doesn't work but if I add this opt in my .select
Test nb 20
and I do this
$localStorage.f.tab.idSelect = 20
$('.select').val($localStorage.f.tab.idSelect).trigger('change');
It works perfectly so how can I make my select2 works with my angularjs and my $localstorage
I have a drop down component in angularjs which when used single time works fine and the values are selected but if I use the same component multiple times in ng-repeat the drop downs are rendered but the values are not being selected. I am using the following code:
JS file:
angular.module('mainApp').component('inputSelectComponent', {
templateUrl : 'sys/templates/input-select.template.html',
bindings : {
ngModel : '='
},
controller: ['$scope', '$element', '$http', 'translate', 'apiServer', 'session', 'EVENTS', function compCategoriesDropdownController($scope, $element, $http, translate, apiServer, session, EVENTS) {
var _select = $element.find('select');
$scope.options = JSON.parse($element.attr('options'));
setTimeout(function(){
$element.find('select').selectize({});
}, 0);
$scope.$watch('$ctrl.ngModel', function(e){
var selectize = _select[0].selectize;
if (typeof(selectize) !== 'undefined') {
setTimeout(function(){
selectize.setValue(e);
}, 0);
}
});
$scope.$watch('$element.attr', function(e){
$scope.label = $element.attr('label');
if ($element.attr('disabled') === 'disabled'){
_select.attr('disabled', 'disabled');
}
});
$element.find('select').on('change', function(e){
$scope.$ctrl.ngModel = e.target.value;
});
}]
});
Template file:
<label class="col-form-label">{{label}}</label>
<select class="cat-drop{{(error!=null)? ' not-validated' :''}}">
<option ng-repeat="(key, value) in options" value="{{key}}">
{{value}}
</option>
</select>
This is how I am calling it:
<div ng-repeat="relatedproduct in relatedproductsData">
<span class="serial-number">{{ $index + 1 }}.</span>
<div class="form-group row">
<input-select-component ng-model="relatedproduct.item_type" class="input-component col-sm-2" label="{{t('related_products_item_type')}}" options='{"2": "2 - For Product", "3": "3 - For Category"}'></input-select-component>
</div>
</div>
Any help is appreciated!
I used a directive instead of an component.
The documentations says:
Components only control their own View and Data: Components should never modify any data or DOM that is out of their own scope. ..
Using a directive allows you to usa ng-model="ngModel" on the select component in the directive and change the value directly.
angular.module('mainApp').directive('inputSelectComponent', function () {
return {
template: `<label class="col-form-label">{{label}}</label>
<select class="cat-drop{{(error!=null)? ' not-validated' :''}}" ng-model="ngModel">
<option ng-repeat="(key, value) in options" value="{{key}}">
{{value}}
</option>
</select>`,
scope: {
ngModel: '=',
options: '=',
}
}
});
it does work in the caller:
<div ng-repeat="relatedproduct in [{ item_type : '' }, {item_type : ''}, { item_type: '' }]">
<span class="serial-number">{{ relatedproduct }}.</span>
<div class="form-group row">
<input-select-component ng-model="relatedproduct.item_type"
class="input-component col-sm-2"
label="{{t('related_products_item_type')}}"
options='{"2": "2 - For Product", "3": "3 - For Category"}'></input-select-component>
</div>
</div>
Good luck!
Try using $timeout instead of setTimeout. Maybe because of angularJS digest...
I'm using angular#1.6.3, bootstrap#3.3.7 and jquery#1.12.4.
I'm trying to wrap a <select> tag into bootstrap-multiselect jQuery plugin.
To do that, I'm trying to use custom directives with an isolated scope.
Here is my HTML:
<div ng-app="myApp" ng-controller="MainCtrl as vc">
<select multiple="multiple"
multiselect
ng-model="vc.selectedCountries"
data-options="vc.allCountries"
data-list-type="Countries">
<optgroup ng-repeat="(continent, countries) in options" label="{{continent}}">
<option ng-repeat="country in countries" value="{{country.code}}">
{{country.code}} - {{country.name}}
</option>
</optgroup>
</multiselect>
</div>
And here is my JS:
var app = angular.module('myApp', [])
app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
var self = this
self.allCountries = {}
$http.get('/countries.json')
.then(function (result) {
self.allCountries = result.data
})
}])
app.directive('multiselect', [function () {
return {
restrict: 'A',
scope: {
options: '=',
listType: '#',
},
transclude: true,
controller: ['$scope', '$element', '$attrs', '$timeout', function ($scope, $element, $attrs, $timeout) {
$scope.$watch('options', function(newVal, oldVal) {
console.log(newVal, oldVal)
$timeout(function () {
console.log($scope.options)
$($element).multiselect('rebuild')
}, 1)
})
$($element).multiselect()
}]
}
}])
However, this way the <select> is never populated.
This is not a problem with the plugin itself, because if I remove the lines containing .multiselect() calls, a regular multiselect appears empty.
I think it's something to do with transclusion and scope, because if I change transclude: true, to transclude: false, and
<optgroup ng-repeat="(continent, countries) in options" label="{{continent}}">
to
<optgroup ng-repeat="(continent, countries) in vc.allCountries" label="{{continent}}">
it works just fine.
However, I'm trying to generalize this component, so I don't want to depend on the controller.
You need not depend on your controller you have written in your code. You can try this alternative.
<!DOCTYPE html>
<html ng-app="exampleApp" >
<head>
<meta charset="utf-8">
<title>ng app</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js" type="text/javascript"></script>
<script>
var myApp = angular.module('exampleApp', []);
myApp.directive('highlight', function(){
return function (scope, element, attrs) {
console.log(scope.$root.list);
}
});
myApp.run(function($rootScope){
$rootScope.list = [1,2,3];
});
</script>
</head>
<body>
<highlight listdata="$parent.list"></highlight>
</body>
</html>
I have 2 DropDowns in MVC and trying to use AngularJS. My first DropDown gets filled with data that comes from the DB properly. When the user makes a selection on the first DropDown, the second DropDown should be filled according to the selection. But, it doesnt get triggered. What am I doing wrong?
When I select from the first DropDown, Chrome Console show this error "undefined". But, it is defined, why does it show this error?
here is my html code...
<form name="mainForm" ng-controller="PriceListEditController" novalidate>
<div class="error">{{message}}</div>
<select id="brandSelect" ng-model="brandSelect" ng-options="b.Id as b.Name for b in brands" ng-change="GetBrandPriceList()">
<option value="">Marka Seçiniz</option>
<option ng-repeat="b.Id for b in brands" value="{{b.Id}}">{{b.Name}}</option>
</select>
<select ng-model="priceList" ng-options="b.Id as b.Name for b in priceLists">
<option value="">-- Select Country --</option>
<option ng-repeat="p.Id for p in priceLists" value="{{p.Id}}">{{p.Name}}</option>
</select>
</form>
here is my JS code...
var app = angular.module('PriceListEditModule', []);
app.controller('PriceListEditController', ["$scope", "$q", "$http", function ($scope, $q, $http) {
$http({
method: 'GET',
url: '/GetBrands'
}).then(function successCallback(response) {
$scope.brands = response.data;
}, function errorCallback(response) {
$scope.message = 'Unexpected Error ' + response.message;
});
$scope.GetBrandPriceList = function () {
console.log($scope.brandSelect);
var brandId = $scope.brandSelect;
if (brandId>0) {
$http({
method: 'GET',
url: '/GetBrandPriceList'
}).then(function successCallback(response) {
$scope.priceLists = response.data;
}, function errorCallback(response) {
$scope.message = 'Unexpected Error ' + response.message;
});
}
else {
$scope.priceList = null;
}
}
}]);
You use ng-options and ng-repeat in the same select section.
Try this in you html:
<form name="mainForm" ng-controller="PriceListEditController" novalidate>
<div class="error">{{message}}</div>
<select id="brandSelect" ng-model="brandSelect" ng-change="GetBrandPriceList()">
<option value="">Marka Seçiniz</option>
<option ng-repeat="b in brands" value="{{b.Id}}">{{b.Name}}</option>
</select>
test
<select ng-model="priceList">
<option value="">-- Select Country --</option>
<option ng-repeat="p in priceLists" value="{{p.Id}}">{{p.Name}}</option>
</select>
</form>
I've created a directive for a select input to select a userId. The model binds from the directive to the rest of the view. However, when I set the id from the controller it doesn't seem to bind to select input in the directive.
Controller:
app.controller('MainCtrl', function($scope) {
// set userId to willem's Id
$scope.userId = 3;
});
Directive:
app.directive('selectUser', function() {
return {
restrict: 'E',
scope: {
ngModel: '='
},
controller: function($scope) {
$scope.users = [{
"id": 1,
"name": 'Tupac'
}, {
"id": 2,
"name": 'Biggie'
}, {
"id": 3,
"name": 'Willem'
}];
},
templateUrl: 'directive.html'
};
});
index.html
<body ng-controller="MainCtrl">
users:
<select-user ng-model="userId"></select-user>
userId = {{userId}}
</body>
directive.html
<select class='form-control focus' ng-model="ngModel">
<option value="">all users</option>
// doesn't bind from the controller. Supposed to show willem, instead of all users to start with.
<option ng-Repeat="user in users" value="{{user.id}}">{{user.name}}</option>
</select>
Working example on: http://plnkr.co/edit/c7eyoB
You should use ngOptions :
<select class='form-control focus' ng-model="ngModel" ng-options="user.id as user.name for user in users">
<option value="">all users</option>
</select>
Then the binding will work. See updated plnkr
Edit, concerning the following question in comment :
could you please explain, why it is not working with ng-repeat?
You can achieve the same visual result with :
<select class='form-control focus' ng-model="ngModel">
<option value="">all users</option>
<option ng-repeat="user in users" value="{{user.id}}" ng-selected="user.id === ngModel">{{user.name}}</option>
</select>
I.e. we added ng-selected="user.id === ngModel".
But this has some drawbacks. First, you are creating unneeded isolated scopes. And also, the values bound to the options are strings, i.e. you will actually select '1', '2' or '3' instead of 1, 2 or 3.