ng change with custom directive - javascript

Javascript code for directive
angular.directive('uiDatePicker', [function() {
return {
restrict: 'EA',
scope: {
ngModel: '=ngModel',
ngChange: '=ngChange'
},
templateUrl: 'complete/date-picker.tmp.html',
replace: true,
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
if(scope.ngModel !== undefined) {
scope.DatePicker = new DatePicker(new Date(scope.ngModel));
} else {
scope.DatePicker = new DatePicker();
}
scope.ngModel = scope.DatePicker.Value;
}
}
}])
Javascript code for controller
angular.controller('Main', ['$scope', function($scope) {
$scope.Change = function(value) {
console.log(value);
};
$scope.Value = 1000;
}])
Html code
<div ng-controller="Main">
<ui-date-picker ng-model="Date" ng-change="Change(Value)"></>
</div>
And my question: How to ng-change work ?. ngModel still work !

Related

AngularJS - Why I cannot get element class name in directive's link function?

I got below code. I expect it will show me true. However, it show me false.
Can anyone explain it to me and provide me a solution to check if the class existed in the element? Thanks in advance.
// HTML
<tit-txt class="{{editable}}" ng-model="mdEnt.phone"></tit-txt>
//JS
.directive('titTxt', function () {
return {
restrict: 'E',
scope: {
ngModel: '=',
},
link: function (scope, element, attrs) {
console.log(element.hasClass('editable'));
},
template: '<input ng-model="ngModel" />',
};
})
Use a watcher to detect when the class is updated:
app.directive('titTxt', function () {
return {
restrict: 'E',
scope: {
myModel: '=',
},
link: function (scope, element, attrs) {
scope.$watch(hasClassEditable, function() {
console.log(element.hasClass('editable'));
});
function hasClassEditable() {
return element.hasClass('editable');
}
},
template: '<input ng-model="myModel" />',
};
})
Interpolated bindings such as class={{editable}} update each digest cycle. The directive needs to wait for a binding to update before using the value.
The DEMO
angular.module("app",[])
.run(function($rootScope,$timeout) {
$rootScope.$timeout = $timeout;
})
.directive('titTxt', function () {
return {
restrict: 'E',
scope: {
myModel: '=',
},
link: function (scope, element, attrs) {
scope.$watch(hasClassEditable, function(value) {
console.log("has class 'editable'", value);
});
function hasClassEditable() {
return element.hasClass('editable');
}
},
template: '<input ng-model="myModel" />',
};
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<input type="checkbox" ng-model="editable" ng-change="$timeout()"
ng-true-value="'editable'" ng-false-value="''" />
add class "editable"
<br>
<tit-txt class="{{editable}}" my-model="inputTxt"></tit-txt>
<br>
editable="{{editable}}"
<br>
inputTxt="{{inputTxt}}"
</body>
Try to do it like this:
// HTML
<div ng-app="myApp" ng-controller="myController">
<tit-txt custom-class="customClass"
cust-var="myVal"></tit-txt>
<div ng-bind="myVal"></div>
</div>
//JS
var app = angular.module('myApp', []);
app.controller('myController', function($scope) {
$scope.customClass = "editable";
$scope.myVal = "this";
});
app.directive('titTxt', function () {
return {
restrict: 'AE',
replace: true,
scope: {
customClass: '=',
custVar: '='
},
link: function (scope, element, attrs) {
console.log(scope);
console.log((scope.customClass === "editable"));
},
template: '<input class="myClass" ng-Model="custVar"/>',
};
})
EDIT: Edited the code to include the working code. Here is the link for plunker
Try this instead:
link: function (scope, element, attrs, controller) {
console.log(angular.element(element).hasClass('editable'));
}
Try with pre function,
link: {
pre: function(scope, element, attr, controllers) {
console.log(element.hasClass('editable'));
},
post: function(scope, element, attr, controllers) {
},
}

AngularJS updating ng-repeat via input not working?

I'm trying to update values in a ng-repeat on a ng-model;
I have the current directive:
app.directive('myDirective', function () {
return {
require: 'ngModel',
restrict: 'E',
template: '<div ng-repeat="e in model"><input ng-model="e"/></div>',
scope: {
ngModel: '='
},
link: function($scope, elem, attrs, ngModelCtrl) {
$scope.$watch(function (){
return ngModelCtrl.$modelValue;
}, function (v) {
$scope.model = ngModelCtrl.$viewValue;
});
}
};
});
but it isn't updating the value as illustrated here:
http://plnkr.co/edit/E89sbXY0gUw53EmJobz0?p=preview
anybody knows what might be wrong?
http://plnkr.co/edit/2JwxNzBRQa1dzACoJIpF?p=preview
Had to replace $scope.model = ngModelCtrl.$viewValue; with scope.model = ngModelCtrl.$viewValue; and it works fine.
app.directive('myDirective', function () {
return {
require: 'ngModel',
restrict: 'E',
template: '<div ng-repeat="e in model"><input ng-model="e"/></div>',
scope: {
ngModel: '='
},
link: function(scope, elem, attrs, ngModelCtrl) {
console.debug()
scope.$watch(function (){
return ngModelCtrl.$modelValue;
}, function (v) {
scope.model = ngModelCtrl.$viewValue;
})
}
};
});
UPDATE: I converted 'stuff' to an array of objects and now it works:
http://plnkr.co/edit/2JwxNzBRQa1dzACoJIpF?p=preview
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.stuff = [{number: 1},{number: 2},{number: 3}];
});
app.directive('myDirective', function () {
return {
require: 'ngModel',
restrict: 'E',
template: '<div ng-repeat="e in model"><input ng-model="e.number"/></div>',
scope: {
ngModel: '='
},
link: function(scope, elem, attrs, ngModelCtrl) {
console.debug()
scope.$watch(function (){
return ngModelCtrl.$modelValue;
}, function (v) {
scope.model = ngModelCtrl.$viewValue;
console.log(scope.model)
})
}
};
});
#Kiwi ng-repeat creates a child scope and ng-model will use the property on the child scope, because ng-model binding will evaluate on the current scope. This is the reason why the json presented in the view doesn't change in your example as it was bound to a property on the child scope created by the ng-repeat directive.
Check this simple jsfiddle example I hope it will be of help to you.
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
{{ctrl.numbers | json}}
<numbers numbers="ctrl.numbers"></numbers>
</div>
</div>
angular
.module('demo', [])
.controller('DefaultController', DefaultController)
.controller('NumbersController', NumbersController)
.directive('numbers', numbers);
function DefaultController() {
var vm = this;
vm.numbers = [1, 2, 3];
}
function numbers()
{
var directive = {
restrict: 'E',
scope: {
numbers: '='
},
template: '<div ng-repeat="number in vm.numbers"><input type="number" ng-model="vm.numbers[$index]"/></div>',
bindToController: true,
controller: NumbersController,
controllerAs: 'vm'
};
return directive;
}
function NumbersController() {
var vm = this;
}

Angular: how to bind to required/ngRequired

I have this directive which can be required or not. It can be used in two ways (as far as I know)
<my-foo required></my-foo>
or
<my-foo ng-required="data.value > 10"></my-foo>
So, because require and ngRequire are basically the same thing you would think that the directive could do this
HTML:
<my-foo ng-require="data.isRequired"></my-foo>
JS:
...
.directive('myFoo', function () {
return {
restrict: 'E',
scope: {
required: '='
}
...
DEMO
Well, nope, this doesn't work, scope.require is undefined. You actually have to change the scope definition to
scope: {
required: '=ngRequired'
}
So the question is what is the preferred way to handle both situation such that the value gets stored in scope.required ? Should I defined both or use attrs from the link function ?
There are basically 2 approaches you can pick:
1. Custom form element supporting ng-model
If you peek at the ng-required directive source code you'll find it only deals with ng-model controller:
restrict: 'A',
require: '?ngModel',
link: function(scope, elm, attr, ctrl) {
if (!ctrl) return;
attr.required = true; // force truthy in case we are on non input element
ctrl.$validators.required = function(modelValue, viewValue) {
return !attr.required || !ctrl.$isEmpty(viewValue);
};
attr.$observe('required', function() {
ctrl.$validate();
});
}
Thus if you custom directive supports ng-model you already have support for ng-required i.e.:
angular.module('test', [])
.directive('myInput', function(){
return {
restrict: 'E',
require: 'ngModel',
scope: true,
template: '<div><button ng-click="changeValue()">Change Value from: {{currentValue}}</button></div>',
link: function (scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$parsers.push(function(val){
if(!val){
return null;
}
return parseFloat(val, 10) * 100;
});
ngModelCtrl.$render = function() {
scope.currentValue = ngModelCtrl.$viewValue || 'No value';
};
scope.changeValue = function read(){
var newValue = Math.random();
if(newValue > 0.5){
ngModelCtrl.$setViewValue(newValue + "");
} else {
ngModelCtrl.$setViewValue(null);
}
ngModelCtrl.$render();
};
}
};
});
2. Wrap existing directive and pass ng-required:
angular.module('test', [])
.directive('myFormElement', function() {
return {
restrict: 'E',
scope: {
model: '=',
required: '='
},
template: '<div>Enter number: <input type="number" ng-model="data.number" ng-required="required"></div>'
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-init="data={value:'Initial', required: false}">
<form>
Is required: <input type="checkbox" ng-model="data.required">
<my-form-element required="data.required" model="data"></my-form-element>
</form>
</div>

Pass an attribute directive to an element directive

I try to pass an attribute directive to an element directive, is it possible? I tried do it as in example but it doesn't work.
for example I have element directive:
<np-form-input
np-form-input-attrs="np-my-attr-directive"
>
</np-form-input>
JS:
.directive('npFormInput', [function () {
return{
restrict: 'E',
templateUrl: '/resources/view/common/form_input',
link: function(scope, element, attr){
scope.attributes= attr.npFormInputAttrs;
}
};
}])
And then in directive HTML
<input
{{attributes}}
>
Thanks in advance.
EDIT: My solution based on Micah Williamson answer:
.run(['$templateCache', '$http', function($templateCache, $http){
$http.get('/resources/view/common/form_input').success(function(data){
$templateCache.put('/resources/view/common/form_input', data);
});
}])
.directive('npFormInput', ['$templateCache', '$compile', function ($templateCache, $compile) {
return{
restrict: 'E',
compile: function (ele, attrs) {
var tpl = $templateCache.get('/resources/view/common/form_input');
tpl = tpl.replace('{{attributes}}', attrs.npFormInputAttrs);
var tplEle = angular.element(tpl);
ele.replaceWith(tplEle);
return function (scope, element, attr) {
$compile(tplEle)(scope);
};
},
};
}])
I've done something similar to what you're trying to do but I had to inject the attributes in the compile. You would need to add the template to $templateCache first though.
.directive('npFormInput', [function ($templateCache, $compile) {
return{
restrict: 'E',
compile: function(ele, attrs) {
var tpl = $templateCache.$get('/resources/view/common/form_input');
tpl = tpl.replace('{{attributes}}', attrs.npFormInputAttrs);
var tplEle = angular.element(tpl);
ele.replaceWith(tplEle);
return function(scope, element, attr){
$compile(tplEle)($scope);
};
}
};
}])

Angular directive event not triggered in compile function

I have tried alot but didn't got success, how can i trigger ng-click in such scenario where it is bind in compile function?
function() {
return {
restrict: 'EA',
compile: function(element, attr) {
return function(scope, element, attr) {
element.html('<div ng-click="save()"></div>');
}
},
controller : function($scope){
$scope.save = function(){
console.log('save');
}
}
};
}
])
Use the link and $compile to produce the results you require:
return {
restrict: 'EA',
link: function (scope, element) {
element.html('<div ng-click="save()">save</div>');
$compile(element.contents())(scope);
},
controller: function ($scope) {
$scope.save = function () {
console.log('save');
}
}
}

Categories

Resources