I have a page where users can rate their performance in different categories. I am using the ui-jq slider for angular and i want to bind the selected value to a model in $scope.
<div ng-repeat="competence in screening_has_skillset.skillset.competences">
<div class="col-sm-12 m-b-md">
<p class="h3">{{competence.competence.name}}</p>
{{competence.competence.level}}
<input id="slider"
ui-jq="slider"
ui-options="{
min: 0,
max: 10,
step: 1,
value: {{competence.competence.level || val }}
}"
ng-model="competence.competence.level"
class="slider slider-horizontal form-control" type="text">
</div>
</div>
I had same problem and write an attribute directive which is named as ng-slider-model for value binding.
.directive('ngSliderModel', ['$parse', function($parse) {
return {
scope: {
ngSliderModel: '=',
uiOptions: '='
},
restrict: 'A',
required: ['ngSliderModel'],
link: function(scope, element, attrs) {
// check there is uiOption or not
var options = ('uiOptions' in attrs) ? scope.uiOptions : {};
// get the value of ngSlider Model
var val = scope.ngSliderModel;
// if value is range [15,25] then return values for uiOptions propertyName else value for singles
var propName = (angular.isArray(val)) ? 'values' : 'value';
/* if you want to slide when the scope value changed not from slider...
watch the ngSliderModel attribute
*/
scope.$watch('ngSliderModel', function(newValue) {
element.slider(propName, newValue);
});
// set value for options
options[propName] = val;
// binding slide event
element.bind('slide', function() {
// Read the current value
var value = element.slider('option', propName);
scope.$apply(function() {
// Apply the value to scope
scope.ngSliderModel = value;
});
});
}
};
}]);;
<input id="slider" ui-jq="slider" value="val" ui-options="{
min: 1,
max: 100,
step: 1,
value: val
}" ui-event="{slideStop: 'updateModel($event)'}" class="slider slider-horizontal form-control" type="text">
value = "val"
do this. in your html element input set the value. where val is scope variable
Related
something similar may have been answered (ng-pattern + ng-change) but all responses were unable to fix this issue.
I have two imbricated directives for creating a form input, a parent directive to control name, label, validator etc. and a child directive to set pattern and input type specific stuff.
However, when setting a pattern, the value on my model is set to undefined when ng-pattern return false.
Directives:
<input-wrapper ng-model="vm.customer.phone" name="phone" label="Phone number">
<input-text type="tel"></input-text>
</input-wrapper>
Generated HTML:
<label for="phone">Phone number:</label>
<input type="text" name="phone"
ng-model="value"
ng-model-options="{ updateOn: \'blur\' }"
ng-change="onChange()"
ng-pattern="/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/">
JS:
angular.module('components', [])
.directive('inputWrapper', function() {
return {
restrict: 'E',
require: 'ngModel',
scope: true,
link: function (scope, element, attrs, ngModel) {
scope.name = attrs.name;
scope.label = attrs.label;
scope.onChange = function () {
ngModel.$setViewValue(scope.value);
};
ngModel.$render = function () {
scope.value = ngModel.$modelValue;
};
}
}
})
.directive('inputText', function() {
return {
restrict: 'E',
template: '<label for="{{name}}">{{label}}:</label><input type="text" name="{{name}}" ng-model="value" ng-model-options="{ updateOn: \'blur\' }" ng-change="onChange()" ng-pattern="pattern">',
link: function (scope, element, attrs) {
if (attrs.type === 'tel') {
scope.pattern = /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/;
}
}
}
});
angular.module('app',['components'])
.controller('ctrl',function($scope){
var vm = this;
vm.customer = {
phone: '010203040506'
};
});
What am I doing wrong ?
Codepen for use case: https://codepen.io/Yosky/pen/yVrmvw
By default in angular if a validator fail, undefined value assigned to ng-model, You can change this setting as follow :
<div ng-model-options="{ allowInvalid: true}">
read here for detail docs
I had some requirements that meant that I really really didn't want ng-model to write out undefined to the scope when validation was invalid, and I didn't want the invalid value either, so allowInvalid didn't help. In stead I just wanted ng-model do not write anything, but I couldn't find any option for this.
So I couldn't see any way forward except for doing some monkey patching of the ng-model controller.
So first I required ngModel in the component I was building require: { model: 'ngModel' } and then I did this in the $onInit hook:
const writeModelToScope = this.model.$$writeModelToScope;
const _this = this;
this.model.$$writeModelToScope = function() {
const allowInvalid = _this.model.$options.getOption('allowInvalid');
if (!allowInvalid && _this.model.$invalid) {
return;
}
writeModelToScope.bind(this)();
};
I also didn't want to take in a new model value while the value was invalid and the component had focus, so I did:
const setModelValue = this.model.$$setModelValue;
this.model.$$setModelValue = function(modelValue) {
_this.lastModelValue = modelValue;
if (_this.model.$invalid) {
return;
}
if (_this.hasFocus) {
return;
}
setModelValue.bind(this)(modelValue);
};
element.on('focus', () => {
this.hasFocus = true;
});
element.on('blur', (event) => {
this.hasFocus = false;
const allowInvalid = this.model.$options.getOption('allowInvalid');
if (!allowInvalid && this.model.$invalid) {
this.value = this.lastModelValue;
}
event.preventDefault();
});
Feel free to judge me, just know that I already feel dirty.
I was working in angular project, There I had come across a situation in which I need to validate custom component having a textbox.
<dollar-text-validate ng-model="ctrl.value" required name="myDir"></dollar-text-validate>
My Component
angular.module("myApp", []);
angular.module("myApp").controller('MyController',function(){
var ctrl = this;
ctrl.value = 56;
});
angular.module("myApp").component('dollarTextValidate',{
bindings: {
ngModel :'='
},
template: '<div><input type="text" ng-focus="ctrl.focus()" ng-blur="ctrl.blur()" ng-model="ctrl.amount1"><input type="hidden" ng-model="ctrl.ngModel"></div>',
controller: function() {
var ctrl = this;
// ctrl.amount1 =
ctrl.amount1 =ctrl.ngModel===undefined||ctrl.ngModel==='' ? '' :'$'+ctrl.ngModel;
console.log(ctrl.ngModel);
ctrl.focus=function(){
ctrl.amount1 = ctrl.amount1 === undefined ? '' : ctrl.amount1.slice(1);
ctrl.ngModel = ctrl.amount1;
console.log(ctrl.ngModel);
}
ctrl.blur=function(){
ctrl.ngModel = ctrl.amount1;
ctrl.amount1 = ctrl.amount1==='' ? '' :'$'+ctrl.ngModel;
console.log(ctrl.ngModel);
}
},
controllerAs:'ctrl'
})
This component is used to set $ symbol in front of entered value. So $ appended value will be available in textbox and original value which is to be validated in hidden field.
How can I validate hidden field. I tried with required attribute in hidden tag but nothing happening. Also tried with custom tag.
Sorry to break it to you, but you might wanna go for directive, and then use $parsers, $formatter and $validators properties of ngModelController.
Component can be used for this, but it is just easier with normal directive.
angular.module('myApp', []);
angular.module("myApp").directive('dollarTextValidate', function() {
return {
require: 'ngModel',
link: function($scope, $element) {
var regexp = /^\$(\d+(\.\d+)?)$/;
var ngModel = $element.controller('ngModel');
ngModel.$formatters.push(function(value) {
return value ? '$' + value : '';
});
ngModel.$parsers.push(function(value) {
var matched = value.match(regexp);
if (matched) {
return +matched[1];
}
});
ngModel.$validators.greaterThan10 = function (modelVal, viewVal) {
var value = modelVal || viewVal;
return value > 10;
};
},
controllerAs: 'ctrl'
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.js"></script>
<div ng-app="myApp" ng-form="form">
dollar-text-validate = <input dollar-text-validate ng-model="value" required name="myDir"><br>
number input = <input type="number" ng-model="value" required><br>
value = {{value}}<br>
errors = {{form.myDir.$error}}
</div>
I want to assign ng-model variable based on condition. For example:
<input type="text" ng-model="item.model[multilang]" >
$scope.multilang can be "ENG","JP"(languages) or false. For example, if multilang = "ENG" and user type in input "Hello",the result will be
item.model = {ENG:"Hello"}
The problem is when $scope.multilang = false , I want the result would be
item.model = "Hello"
I can't find a way to achieve above result. I think one solution is changing ng-model based on $scope.multilang so when it's false,it will change ng-model of input to be = ng-model="item.model" but I don't know how to do this.
EDITED
I thought of one solution:
<input ng-if="multilang" type="text" ng-model="item.model[multilang]" >
<input ng-if="!multilang" type="text" ng-model="item.model" >
but there is better way to achieve ?
-----plnkr example-----
Angular is very flexible and powerful framework. You should use custom directive and ngModel's getter/setter option.
Directive without ngModel's getter/setter may look like this:
<input type="text"
ng-model="val"
multilang="multilang"
multilang-model="item.model">
Directive code:
.directive('multilang', [function(){
return {
restrict: "A",
require: "ngModel",
scope: {
multilang: "=",
multilangModel: "="
},
link: function(scope, element, attr, ngModel){
ngModel.$viewChangeListeners.push(function()){
var value = ngModel.$modelValue;
if(scope.multilang !== false) {
if(typeof scope.multilangModel == 'undefined')
scope.multilangModel = Object.create(null)
scope.multilangModel[scope.multilang] = value
}
else {
scope.multilangModel = value
}
})
}
}
}])
--forked plunkr--
In case of using ngModel's getter/setter
<input type="text"
ng-model="val"
multilang="multilang"
multilang-model="item.model"
ng-model-options="{ getterSetter: true }">
Directive code:
.directive('multilang', [function(){
return {
restrict: "A",
scope: {
multilang: "=",
multilangModel: "=",
val: "=ngModel"
},
link: function(scope, element, attr){
scope.val = function(newValue) {
if(scope.multilang !== false) {
if(typeof scope.multilangModel == 'undefined')
scope.multilangModel = Object.create(null)
return arguments.length ? (scope.multilangModel[scope.multilang] = newValue) : scope.multilangModel[scope.multilang];
}
else {
return arguments.length ? (scope.multilangModel = newValue) : scope.multilangModel;
}
}
}
}
}])
--forked plunkr--
In my opinion, second one is better. It has two way binding with item.model and changes input value when item.model was changed in other place of code.
Try this:
<input ng-show="multilang" type="text" ng-model="item.model[multilang]" >
<input ng-hide="multilang" type="text" ng-model="item.model" >
I have a few radio buttons with certain value. What I'm trying to achieve is, on selecting certain radio buttons, it's value should add up and be displayed as total.
Here is my AngularJS directive and controller code :
angular.module('mapp',[])
.controller('ctrl',['$scope',function($scope){
$scope.items = [
{'Id':1, 'Cost':100},
{'Id':2,'Cost':200}
];
$scope.total = 0;
}])
.directive('customElement',function(){
return {
restrict: 'E',
scope:{
data: '=info'
},
template: '<input type="radio" ng-model="data">\
<span>{{data}}</span>'
}
});
And here is the HTML code:
<div ng-app="mapp">
<div ng-controller="ctrl">
<custom-element ng-repeat="item in items" info="item.Cost"></custom-element>
<br/>
<br/> Total: <span>{{total}}</span>
</div>
</div>
And here is a DEMO.
You can do that by passing in two different arguments to the directive: data (for the label) and then a secondary boolean selected to determine whether the item is selected or not.
Javascript:
angular.module('mapp',[])
.controller('ctrl',['$scope',function($scope){
$scope.items = [
{'Id':1, 'Cost':100, selected: false},
{'Id':2,'Cost':200, selected: false}
];
$scope.total = function () {
var selectedItems = $scope.items.filter(function (d) { return d.selected; });
console.log('items = ', $scope.items);
var totalSum = 0;
selectedItems.forEach(function (item) {
totalSum += item['Cost'];
});
return totalSum;
};
}])
.directive('customElement',function(){
return {
restrict: 'E',
scope:{
data: '=info',
selected: '=selected'
},
template: '<input type="radio" ng-model="selected" ng-value="true">\
<span>{{data}}</span>'
}
});
HTML:
<custom-element ng-repeat="item in items"
info="item.Cost"
selected="item.selected">
</custom-element>
Finally, you'll need to calculate the total via a getter.
Demo: http://jsfiddle.net/vv46xs0c/
I haven't succeeded with radio buttons (I don't know much about this thing :-(, and I could not "uncheck" the radio buttons ), but I've succeeded with checkboxes
Here is your updated fiddle : http://jsfiddle.net/8kpddb92/4/
What did I have to change :
ng-model needed a boolean
adding a function inside your controller
$scope.handleChange = function(){
$scope.total = 0;
for (var i=0; i < $scope.items.length; i++){
if ($scope.items[i].isSelected)
$scope.total += $scope.items[i].Cost;
}
}
And calling this function inside the child directive :
template: '<input type="checkbox" ng-model="data.isSelected" ng-change=$parent.handleChange()>\
<span>{{data.Cost}}</span>'
No need to make a new scope. Just use the 'item' from the repeat. Call a change function on click, pass the item, and you are good to go :)
angular.module('mapp',[])
.controller('ctrl',['$scope',function($scope){
$scope.items = [
{'Id':1, 'Cost':100},
{'Id':2,'Cost':200}
];
$scope.total = 0;
$scope.change = function(item) {
$scope.total = item.Cost;
};
}])
.directive('customElement',function(){
return {
restrict: 'E',
template: '<input type="radio" name="radios" ng-click="change(item)"><span>{{item.Cost}}</span>'
}
});
Hi I have situation where I have to format certain values using ng-init as well as have ng-model for two way binding in input field so value can be changed and saved.
<div ng-repeat="ab in ablist">
<div class="col-sm-3">
<input type="text" ng-init="item.ab=fn(item.ab)" ng-model="item.ab" />
</div>
</div>
The above code doesnt work. It does not show the formatted value.
Can you let me know how I can change this so I can display the formatted value using ng-init but as well as keep ng-model for binding edited value on submit.
In this case you have to use directive. ng-init is to be used when you want to set some default or initial value to any control. Directive can keep your display value and your model value in separate formats. Here is a directive for formatting integers with commas.
app.directive('formattednumber', function () {
return {
link: function (scope, element, attrs, ctrl) {
element.bind('blur', function (blurEvent) {
if (element.data('old-value') !== element.val()) {
// console.log('value changed, new value is: ' + element.val());
scope.$apply(function () {
var v = number_format(element.val(), 0, 0, 99999999999);
element.val(v);
//scope.myDirective = element.val();
//element.data('old-value', element.val());
});
}
});
ctrl.$formatters.unshift(function (modelValue) {
if(!modelValue) modelValue="0";
if(modelValue.replace &&(isNaN(parseFloat(modelValue)) || !isFinite(modelValue)))
{
modelValue = parseFloat(modelValue.replace(/,/g, ""));
}
var v = number_format(modelValue, 0, 0, 99999999999);
v = v == undefined? 0 : v;
element.val(v);
return v;
});
ctrl.$parsers.unshift(function (viewValue) {
if(!viewValue) viewValue="0";
viewValue = parseInt(viewValue.replace(/,/g, ""));
var v = number_format(viewValue, 0, 0, 99999999999);
v = v == undefined? 0 : v;
element.val(v);
return viewValue;
});
},
restrict: 'A',
require: 'ngModel'
}
});
Similarly, you can write one for date formatting. You can use Date.js for the same.
The usage is :
<input type="text" ng-model="item.amount" formattednumber />
What about this:
<div ng-repeat="ab in ablist">
<div class="col-sm-3">
<input type="text" ng-init="item=fn(ab)" ng-model="item" />
</div>
</div>