Not sure how to phrase the question so please edit if you can come up with something better. I have the following directive:
app.directive('foo', function() {
return {
restrict: 'A',
require: "?ngModel",
link: function (scope, element, attrs, controller) {
scope.$watch(attrs.ngModel, function () {
console.log("Changed to " + scope[attrs.ngModel]);
});
}
};
});
When I have this it works great and logs properly
<input type="text" ng-model="bar" />
app.controller('fooController', function($scope) {
$scope.bar = 'ice cream';
});
It doesn't work when I try it this way around. It keeps logging 'Changed to undefined'
<input type="text" ng-model="model.bar" />
app.controller('fooController', function($scope) {
$scope.model = { bar: 'ice cream' };
});
How do I make it work for both scenarios. It seems the right thing to do seeing as angular lets you use both.
I looked at ngModel directive and found a function called ngModelGet. Uses $parse.
app.directive('foo', function($parse) {
return {
restrict: 'A',
require: "?ngModel",
link: function (scope, element, attrs, controller) {
var ngModelGet = $parse(attrs.ngModel);
scope.$watch(attrs.ngModel, function () {
console.log("Changed to " + ngModelGet(scope));
});
}
};
});
your can use
var ngModelCtrl = controller;
ngModelCtrl.$viewValue
replace
scope[attrs.ngModel]
here is ngModelCtrl sdk
Related
I have a directive and I'm trying to pass Date/moment object via attribute. I'm passing it like this: (I know, that I can create isolated-scope and bind it, it is not the case)
<form name="form">
<input name="field" ng-model="fieldModel" form-field-directive field-date="{{fieldDateModel}}" />
</form>
Without curly brackets the result is obvious, but with I'm getting such quoted string "2015-07-03T10:35:13.691Z".
Is there anyway to work with it?
UPDATE:
angular.module('app', [])
.controller('AppCtrl', function($scope) {
$scope.fieldDateModel = moment(); // new Date()
});
angular.module('app')
.directive('formFieldDirective', function() {
return {
restrict: 'A',
require: '^ngModel',
link: function(scope, iElement, iAttrs, ngModelCtrl) {
ngModelCtrl.$validators.fieldDate = function() {
if (angular.isUndefined(iAttrs.fieldDate)) {
return true;
}
console.log(iAttrs.fieldDate);
};
}
};
});
You can actually pull the value from the parent scope using $parse which is more reliable.
angular.module('app')
.directive('formFieldDirective', function($parse) {
return {
restrict: 'A',
require: '^ngModel',
link: function(scope, iElement, iAttrs, ngModelCtrl) {
ngModelCtrl.$validators.fieldDate = function() {
if (angular.isUndefined(iAttrs.fieldDate)) {
return true;
}
console.log(($parse(iAttrs.fieldDate)(scope)).format());
};
}
};
});
http://jsbin.com/qoheraloge/1/edit?js,console,output
I am trying to convert number into currency suppose if user enter 5 in textbox i want to auto correct it like $5.00 for that i am trying to write directive but no idea how to make it work as working on directive for fist time.
(function () {
'use strict';
angular.module('commonModule')
.directive('srCurreny', function (utilSvc) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, model) {
element.bind('blur', function (event) {
var val = element.val();
if (!utilSvc.isEmptyOrUndefined(val)) {
var transform = currency + " " + val.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,");
model.$setViewValue(element.val(transform));
scope.$apply();
}
});
}
};
});
})();
JS
Set the amount in the Controller first.
angular.module('commonModule')
.controller('aController', ['$scope', function (scope) {
scope.amount = 5;
}])
.directive('srCurrency', ['$filter', function ($filter) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, el, attrs, ngModel) {
function onChangeCurrency () {
ngModel.$setViewValue($filter('currency')(ngModel.$viewValue, '$'));
ngModel.$render();
}
el.on('blur', function (e) {
scope.$apply(onChangeCurrency);
});
}
}
}]);
HTML
<div ng-app='app' ng-controller="aController">
<input type="text" sr-currency ng-model='amount' />
</div>
JSFIDDLE
I recommend using the build-in currency filter of Angular, or, if that doesn't meet your needs you can create your own.
https://docs.angularjs.org/api/ng/filter/currency
Was wondering how I should handle async functions in $parsers.
The below code doesn't update the scope.
I'm using AngularJS 1.2 so can't make use of the new and fancy 1.3 features.
http://plnkr.co/edit/uk9VMipYNphzk8l7p9iZ?p=preview
Markup:
<input type="text" name="test" ng-model="test" parse>
Directive:
app.directive('parse', function($timeout) {
return {
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
$timeout(function() {
return viewValue;
});
});
}
};
});
If you are looking for async validation function, I did something like that some time ago and release it as a library. Check the custom-remote-validator directive here.
The basic idea was use ngModelController $setValidity after receiving validation result from server. This is the directive source code
.directive('customRemoteValidator', [function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elm, attr, ngModelCtrl) {
var validateFunctionNames = attr["remoteValidateFunctions"].split(",");
var validatorNames = attr["customRemoteValidator"].split(",");
ngModelCtrl.$parsers.push(function (value) {
angular.forEach(validateFunctionNames, function (functionName, index) {
if (!scope[functionName]) {
console.log('There is no function with ' + functionName + ' available on the scope. Please make sure the function exists on current scope or its parent.');
} else {
var result = scope[functionName](value);
if (result.then) {
result.then(function (data) { //For promise type result object
ngModelCtrl.$setValidity(validatorNames[index], data);
}, function (error) {
ngModelCtrl.$setValidity(validatorNames[index], false);
});
}
}
});
return value;
});
}
};
}])
I have a directive for an upload file that communicates with the server and returns a scope.dbInsertId. I want to watch this and then update the ng-model with this value. I am unable to get it to work using $apply. Here is my code:
scope.$watch('dbInsertId', function(newValue, oldValue) {
if (newValue)
scope.$apply(function() {
scope.ngModel = scope.dbInsertId;
});
console.log("I see a data change!");
return ngModel.$modelValue;
}, true);
Is my code wrong?
My answer for your question
<div ng-app="app">
<div ng-controller="MyController">
<form name="someForm">
<div this-directive ng-model="theModel"></div>
<div>theModel='{{ theModel }}'</div>
</form>
</div>
</div>
var app = angular.module('app', []);
app.controller('MyController', function($scope,$rootScope,$log) {
$scope.theModel = '';
$scope.$watch('theModel',function(newVal,oldVal){
$log.info('in *MyController* model value changed',newVal,oldVal);
});
});
app.directive('thisDirective', function($compile, $timeout, $log) {
return {
scope: {
ngModel: '='
},
require: 'ngModel',
template: '<input type="text" ng-model="ngModel" /><div child-directive ng-model="ngModel"></div>',
link: function(scope, element, attrs, ngModel) {
}, // end link
} // end return
});
app.directive('childDirective', function($compile, $timeout, $log) {
return {
scope: {
ngModel: '='
},
template: '<input type="text" ng-model="ngModel" />',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
},
} // end return
});
jsfiddle.net/dXL4w/3
You need scope:
scope.$watch('dbInsertId', function(newValue, oldValue, scope) { // here
if (newValue)
scope.$apply(function() {
scope.ngModel = scope.dbInsertId;
});
console.log("I see a data change!");
return ngModel.$modelValue;
}, true);
I am using ng-repeat and setting a model with it similar to the following
<div ng-repeat="thing in things" ng-model="thing" my-directive>
{{thing.name}}
</div>
then in my directive it looks something like this
.directive("myDirective, function () {
return {
require: 'ngModel',
link: function(scope, lElement, attrs, model) {
console.log(model.name);// this gives me 'NAN'
}
}
})
My question is how can I access the values in the model? I tried model.$modelValue.name but that did not work.
If you want to bind in a scoped value then you can use the '=' in an isolated. This will appear on the scope of your directive. To read the ng-model directive, you can use =ngModel:
.directive("myDirective", function () {
return {
scope: {
model: '=ngModel'
}
link: function(scope) {
console.log(scope.model.name); // will log "thing"
}
}
});
.directive("myDirective", function () {
return {
require: 'ngModel',
link: function(scope, lElement, attrs, model) {
console.log(attrs.ngModel); // will log "thing"
}
}
})
If your directive does not have isolated or child scope then you can do this:
.directive('someDirective', function() {
return {
require: ['^ngModel'],
link: function(scope, element, attrs, ctrls) {
var ngModelCtrl = ctrls[0];
var someVal;
// you have to implement $render method before you can get $viewValue
ngModelCtrl.$render = function() {
someVal = ngModelCtrl.$viewValue;
};
// and to change ngModel use $setViewValue
// if doing it in event handler then scope needs to be applied
element.on('click', function() {
var val = 'something';
scope.$apply(function() {
ngModelCtrl.$setViewValue(val);
});
});
}
}
});