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...
Related
The ng-repeat show default empty string for first option. Why in may case it does not work. What is wrong in here?
My angular code is here. What i mistake here. I don't understand.
var exchange = angular.module('app', []);
exchange.controller('ExchangeController', ExchangeController);
function ExchangeController($scope, $http) {
$http
.get(window.location.origin + "/api/get-item/", {
transformRequest: angular.identity,
headers: {'Content-Type': undefined, 'Process-Data': false}
})
.then(function(response){
$scope.items = response.data.items;
$scope.send_item_id = $scope.items[0].value;
});
$scope.getSendItem = function() {
var send_item_id = $("#send_item_id").val();
console.log(send_item_id);
}
}
Here is my html code,
<div class="form-group">
<div class="col-md-12 col-sm-12">
<select data-plugin-selectTwo
name="send_item_id"
id="send_item_id"
ng-model="send_item_id"
ng-change="getSendItem()"
class="form-control populate">
<option ng-repeat="item in items" value="#{{ item.value }}">#{{ item.text }}</option>
</select>
</div>
</div>
You need to manually select a "selected" item (itemSelected model in my solution) and change your value attribute to ng-value to make it work in the AngularJS way. Please check this demo fiddle I've created for you. Btw. you don't need jQuery here: please check how I log the selected item in getSendItem(). This will work for AngularJS 1.6.x or later.
View
<div ng-controller="MyCtrl">
<select data-plugin-selectTwo
name="send_item_id"
id="send_item_id"
ng-model="itemSelected"
ng-change="getSendItem()"
class="form-control populate">
<option ng-repeat="item in data" ng-value="item.value">
#{{ item.text }}
</option>
</select>
</div>
AngularJS application
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope) {
$scope.data = [{
"text": "Bkash",
"value": 1
}, {
"text": "Paypal",
"value": 2
}];
$scope.itemSelected = $scope.data[0].value;
$scope.getSendItem = function() {
console.log($scope.itemSelected);
}
});
While using AngularJS 1.5.x or earlier you need to do it like in this demo fiddle by using ng-selected:
View
<div ng-controller="Controller">
<select name="send_item_id"
id="send_item_id"
ng-model="itemSelected"
ng-change="getSendItem()">
<option
ng-repeat="item in data" value="{{ item.value }}"
ng-selected="{{item.value === itemSelected}}">
{{ item.text }}
</option>
</select>
</div>
AngularJS application
var myApp = angular.module('app', []);
myApp.controller('Controller', function($scope) {
$scope.data = [{
"text": "Bkash",
"value": 1
}, {
"text": "Paypal",
"value": 2
}];
$scope.itemSelected = String($scope.data[0].value);
console.log($scope.itemSelected);
$scope.getSendItem = function() {
console.log($scope.itemSelected);
}
You need to match the option value and ng-model value in order to prevent the default empty space. in your case it does not match since there is # symbol in front of your option value. remove it.
<option ng-repeat="item in items" value="{{ item.value }}">#{{ item.text }}</option>
Try this. It's working for me.
<option value="{{item.value}}" ng-repeat="item in items" ng-selected="$first">{{ item.text }}</option>
I've been struggling and Googling everywhere around and I can't imagine why this directive doesn't update my controller $scope value:
Directive:
app.directive('ingFormField', function () {
return {
restrict: "E",
scope: {
value: "=",
fieldName: "#",
fieldLabel: "#"
},
div class="form-group">'+
' <label for="{{fieldName}}" class="control-label">{{fieldLabel}}:</label>'+
' <input ng-model="value" class="form-control" type="text" name="{{fieldName}}" id="{{fieldName}}" />' +
'</div>'
};
});
used in HTML:
<ing-form-field field-name="Order" field-label="Order" ng-model="lateral.Order"></ing-form-field>
And my object "lateral" from my controller:
$scope.lateral = {Order: "01", Name: "Person"}
I've tried some functions from StackOverflow answers about using a link function to update values in my controller $scope with the same output: values from $scope to the directive are working but any change on the directive's input field don't update $scope object "lateral"
This may be has an alternative aproach by using ngModel parameter directly and pass it through your template. Using ngModel will help you to keep consistence of naming things on your template.
For example, if you use your directive template using the ngModel directive, you can call it from the directive scope and use it do reflect the model to your parent controller.
The following code implement this solution, be aware that this is one of the solution, you may find different ways to do that.
angular
.module('myApp', [])
.directive('ingFormField', function() {
return {
restrict: "E",
scope: {
ngModel: "=",
fieldName: "#",
fieldLabel: "#"
},
template: '<div class="form-group">' +
' <label for="{{fieldName}}" class="control-label">{{fieldLabel}}:</label>' +
' <input ng-model="ngModel" class="form-control" type="text" name="{{fieldName}}" id="{{fieldName}}" />' +
'</div>'
};
})
.controller('myController', function($scope) {
$scope.lateral = {
Order: "01",
Name: "Person"
}
});
angular.element(document).ready(function() {
angular.bootstrap(document, ['myApp']);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<div ng-controller="myController">
<ing-form-field field-name="Order" field-label="Order" ng-model="lateral.Order">
</ing-form-field>
<pre>{{ lateral | json }}</pre>
</div>
Please see below code, you're very close. I think you may have been trying to set/pass the value using ngModel instead of the scoped property you designated for it, which was value. That's if I'm understanding correctly. Please let me know if this helps, if not I can always update.
function exampleController($scope) {
$scope.lateral = {
Order: "01",
Name: "Person"
};
}
function ingFormField() {
return {
restrict: "E",
scope: {
value: "=",
fieldName: "#",
fieldLabel: "#"
},
template: '<div class="form-group"> ' +
' <label for="{{fieldName}}" class="control-label">{{fieldLabel}}:</label>' +
' <input ng-model="value" class="form-control" type="text" name="{{fieldName}}" id="{{fieldName}}" />' +
'</div>'
};
}
angular
.module('example', [])
.controller('exampleController', exampleController)
.directive('ingFormField', ingFormField);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<div class="container-fluid" ng-app="example">
<div class="container" ng-controller="exampleController">
<ing-form-field field-name="Order" field-label="Order" value="lateral.Order"></ing-form-field>
</div>
</div>
I have a custom directive being used like so:
<drop-down-filter-field
model="my_model.property"
options="{ list: property_options, field: 'code' }"
></drop-down-filter-field>
With the directive code (field is another directive that groups together some common markup for errors and layout etc):
<field label="label" field="field" model="model" display="display" annotation="annotation">
<select
ng-model="$parent.model"
ng-change="setValue(item.value, item[options.field])"
>
<option ng-repeat="item in options.list" value="{{item.value}}">{{item[options.field]}}</option>
</select>
</field>
I tried to add the ng-change to manually set my model value, since the drop down isn't working. But, the function in ng-chang isn't firing either.
And Directive
angular.module('my-app')
.directive('dropDownFilterField', function($compile) {
return {
restrict: 'E',
templateUrl: 'views/directives/form-elements/drop-down-filter-field.html',
controller: 'dropDownFilterField',
scope: {
model: '=',
label: '=',
field: '=',
options: '=',
annotation: '=',
}
};
})
.controller('dropDownFilterField', function($scope, $element, $parse) {
$scope.setValue = function(value) {
self.$scope.model = value;
};
})
;
I already have this pattern with the nested directive with "$parent.model", functioning in several other templates/directives, for example, an input tag:
<field label="label" field="field" model="model" annotation="annotation" validate="validate">
<input type="text" name="{{formname}}" ng-model="$parent.model" ng-required="{{required}}" placeholder="{{field.default}}"
uib-typeahead="{{'typeAheadItem' + (options.field ? '.' + options.field : '')}} as {{'typeAheadItem' + (options.field ? '.' + options.field : '')}} for typeAheadItem in options.list | filter:$viewValue | limitTo:{{options.limit || 8}}"
ui-validate="'validateFunction($value)'"/>
</field>
All of my other custom directives that contain inputs, and textareas are working, but I can't get it working for select. Anyone know why this might be ?
Have you tried using ng-options?
<select
ng-model="$parent.model"
ng-options="item.value as item[options.field] for item in options.list"
>
</select>
There should be no need to use ng-change to update ng-model value, the two-way-binding of ng-model should update itself.
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.
I might be missing something stupidly as this simple code doesn't work as expected. What is wrong is the $scope.change function in the MainCtrl doesn't work (no alert box popped up).
In a nutshell, the view is (it's in jade, better to view?)
<body ng-app="epfApp">
...
label(ng-repeat="question in questions")
| {{ question.title }}
input(type="{{question.type}}", ng-change="change()")
and in the controller file
angular.module('epfApp')
.controller('MainCtrl', function ($scope, $window) {
$scope.questions = {
'1': {
'title': 'The first question is?',
'type': 'text',
'placeholder': 'first question'
},
'2': {
'title': 'The second question is?',
'type': 'text',
'placeholder': 'second question'
}
};
$scope.change = function() {
$window.alert('text');
};
});
And the route:
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
});
Now what it is doing properly is that it correctly populates the view with the data created (i.e. the questions json). However, What it is not doing properly is the change() function bound to the input textbox doesn't work.
What am I missing here? This obviously is a very basic job.
ng-change requires ng-model as well.
<div ng-controller="MainCtrl">
<label ng-repeat="question in questions">
{{question.title}}
<input type="{{question.type}}" ng-model="question.placeholder" ng-change="change()" />
<br />
</label>
</div>
Check out this JSFiddle.
ng-change not working but it work if you define ng-model="yourValue"... like this
<select id="editSelect" ng-model="Option" ng-change="okChange()" name="Option">
<option ng-repeat="data in Option" value="{{data.Option}}">{{data.Option}}</option>
</select>
<div ng-app ng-controller="myCtrl">
<input type="file" ng-model="image" onchange="angular.element(this).scope().uploadImage()" />
<ul>
<li ng-repeat="item in uploadcollection">
{{item.name}} ({{item.size}})
</li>
</ul>
function myCtrl($scope) {
$scope.uploadImage = function () {
$scope.uploadcollection.push({name: "Income.pdf", size: "10mb"});
$scope.$apply();
}
$scope.uploadcollection = [{name: "Income.pdf", size: "10mb"}, {name: "Expense.pdf", size: "1.5mb"}];
}
I have created a demo here: http://jsfiddle.net/fA968/120/
NOTE: This Example not worked with v1.4.8: https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js
Update
Here is an simple way to do this:
var myApp = angular.module('myApp', []);
myApp.directive('customOnChange', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var onChangeFunc = scope.$eval(attrs.customOnChange);
element.unbind('change').bind('change', function(e) {
onChangeFunc(e);
});
}
};
});
Here is an updated Fiddle
When the expression inside of the ng-change="" is something which errors (like with a spelling error) it will not log the error to the console. You will not know anything is amiss except for the fact that nothing happens.
Make sure to spell things correctly and to prefix the alias you give the "Controller As" syntax, if applicable.