I am unable to get $apply inside $watch to work - angularjs

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);

Related

How can I access to ngModel of an input from a parent Directive / angularjs

I have this view
<div my-directive="somevalue">
<input name="myField" ng-model="dataForMyField">
</div>
And this is my directive
app.directive('myDirective', function ($compile) {
return {
restrict: 'A',
template: `<div ng-transclude=""></div>
<div>SomeValue from directive <strong>{{ someReturnedValue }}</strong></div>`,
transclude: true,
controller: function($scope, $element, $attrs, $transclude) {
$scope.someReturnedValue = 'ValueFromDirective';
console.log('Name of input'); // myField
$scope.$watch('vm.ngModel', function(newValue, oldValue, scope) {
console.log('WOW! Input.ngModel changed', newValue); // world in the init
});
}
}
})
How can I access to ngModel of input.
---------> here is a plkr: http://plnkr.co/edit/nWNAuf9jbv0sgY2VYRtZ?p=preview
Try this
<div my-directive="somevalue">
<input name="myField" ng-model="dataForMyField">
</div>
app.directive('myDirective', function () {
return {
scope: {
dataForMyField: '#dataAttr'
},
restrict: 'A',
template: `<div ng-transclude=""></div>
<div>SomeValue from directive <strong>{{ someReturnedValue }}</strong></div>`,
transclude: true,
controller: function($scope, $element, $attrs, $transclude) {
$scope.someReturnedValue = 'ValueFromDirective';
console.log('Name of input'); // myField
}
}
})

Why my Angular directive input is not been posted?

I'm trying create a directive to reuse in a form. But when I submit, the input (directive) is not there.
This is my tag:
<core-input type="text" icon="person" name="name" placeholder="Name" ng-model="mymodel.name"></core-input>
This is my directive js code:
angular.module('StarterApp').directive('coreInput', function($compile) {
return {
restrict: 'AE',
require: '?ngModel',
scope: true,
link: function(scope, element, attrs, ngModel) {
if (!ngModel) return;
scope.onChange = function() {
ngModel.$setViewValue(scope.value);
};
ngModel.$render = function() {
scope.opts = attrs;
scope.value = ngModel.$modelValue;
$compile(element.contents())(scope);
};
},
templateUrl: function(elem, attr) {
return './app/views/directives/form/' + attr.type + '.html';
}
};
});
And this is what I want reuse:
<md-input-container class="md-icon-float md-block" flex-gt-sm md-no-float>
<md-icon class="material-icons">
<i class="material-icons">{{ opts.icon }}</i>
</md-icon>
<input type="text" name="{{ opts.name }}" placeholder="{{ opts.placeholder }}" ng-model="$parent.ngModel">
</md-input-container>
What am I missing here?
The angular documentation states that $setViewValue don't call the $render method on ngModel. So this have to be called manually. As the html of the element has changed shiould be possible to retrieve the original template from the angular service $templateCache
var urlPrefix = './app/views/directives/form/';
var templateExtension = '.html';
angular.module('StarterApp').directive('coreInput',['$compile', '$templateCache' function($compile, $templateCache) {
return {
restrict: 'AE',
require: '?ngModel',
scope: true,
link: function(scope, element, attrs, ngModel) {
if (!ngModel) return;
scope.onChange = function() {
ngModel.$setViewValue(scope.value);
ngMode.$render();
};
ngModel.$render = function() {
var template = $templateCache.get(urlPrefix + attrs.type + templateExtension);
element.html(template);
$compile(element.contents())(scope);
};
},
templateUrl: function(elem, attr) {
return urlPrefix + attr.type + templateExtension;
}
};
}]);

Show all applied filters of smart-table

I want to display all applied filters of smart-table in a div. My idea was to write a directive that watches the ctrl.tableState().search.predicateObject property:
directivesModule.directive('filterBar', function() {
return {
restrict:'E',
require:'^stTable',
template: '<div class="row"><div class="col-xs-12 filters"><span class="filters-header">Filters: </span><span class="tag label label-default" ng-repeat="filter in filters"><span>{{filter.name}}</span><a><i class="remove glyphicon glyphicon-remove-sign glyphicon-white"></i></a> </span> </div> </div>',
scope: true,
link:function(scope, element, attr, ctrl){
scope.$watchCollection(ctrl.tableState().search.predicateObject, function(newVal, oldVal) {
console.log(newVal, oldVal);
});
}
};
});
However the console.log is only called once showing undefinded twice.
I use the following code to add a filter:
directivesModule.directive('addFilter', function() {
return {
restrict:'A',
require:'^stTable',
scope: {
criterion: '#',
value: '#'
},
link:function(scope, element, attr, ctrl){
element.bind('click', function() {
scope.$apply(function() {
ctrl.search(scope.value, scope.criterion);
console.log(ctrl.tableState().search.predicateObject);
});
});
}
};
});
As a solution I went for ngTable. This made it much easier. I use this code now:
"use strict";
var directivesModule = angular.module("directives");
directivesModule.directive('addFilter', function() {
return {
restrict:'A',
scope: {
criterion: '#',
value: '#',
filter: '='
},
link:function(scope, element){
element.bind('click', function() {
scope.$apply(function() {
scope.filter[scope.criterion] = scope.value;
});
});
}
};
});
I am not sure to understand why you are watching a collection here
why not doing something like:
DirectivesModule.directive('filterBar', function() {
return {
restrict:'E',
require:'^stTable',
template: 'you template',
scope: true,
link:function(scope, element, attr, ctrl){
scope.$watch(function () {
return ctrl.tableState().search;
}, function (newValue, oldValue) {
if(newValue.predicateObject){
console.log(newValue.predicateObject)
}
}, true);
}
};
});

Same directive to multiple inputs. it's possible? AngularJS

I hope u can help me.
I have a directive:
.directive('checkField', ['$http', function($http) {
return {
require: 'ngModel',
restrict: 'A',
link: function (scope, ele, attrs, c) {
scope.$watch(function() {
if (attrs.ngModel === 'data.gender_value' && ele.val() !== '') {
//valid
} else {
//error
}
if (attrs.ngModel === 'data.cardholder_value' && ele.val() !== '') {
//valid
} else {
//error
}
});
},
template: ''
};
}])
And i have multiple inputs in my html:
<input ng-model="data.cardholder_value" type="text" size="50" data-check-field />
<input ng-model="data.gender_value" type="text" ng-required="true" data-check-field />
The problem is that watch trigger only "see" the first input, no more.
I'm trying to use de same directive to multiple inputs, but doesn't work. If i do an alert, to check the attribute name of field, always display "data.cardholder_value", never other name field.
Thank u in advance.
Edit 1:
This is my html calling (ng-include):
<form method="post" id="formQuestion" name="formQuestion" ng-submit="sendForm()" novalidate ng-controller="questionForm">
{{data | json}}
<div class="slide-animate" ng-include="'/templates/default/partials/_fields/1_card_type.html'"></div>
<div class="slide-animate" ng-include="'/templates/default/partials/_fields/2_gender.html'"></div>
My app controller:
angular.module('app.controllers')
.directive('checkField', ['$http', function($http) {
return {
require: 'ngModel',
restrict: 'A',
link: function (scope, ele, attrs, ctrl) {
scope.$watch(attrs.ngModel, function(val) {
console.log(attrs.ngModel, attrs.name, val)
});
},
template: ''
};
}])
.controller('questionForm', ['$scope', '$http', 'fieldApiService', function ($scope, $http, fieldApiService) {
...
All you just need it to watch the value of ng-model directive attribute, right now you provided the watcher function as your validation function which mean when it sees function as first argument for the watch it will just only look for the return value from that function to determine if watch listener needs to run or not during every digest cycle.
scope.$watch(attrs.ngModel, function(val) {
if (!val) {
//valid
} else {
//error
}
});
Also remember if you want to catch the user entered values you can always use the existing $viewChangeListener property on ngmodel, it will avoid reuse of existing internal watcher and no need to explicitly create one.
c.$viewChangeListeners.push(function(){
console.log('viewChange', ctrl.$viewValue)
});
Demo
angular.module('app', []).directive('checkField', ['$http',
function($http) {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, ele, attrs, ctrl) {
scope.$watch(attrs.ngModel, function(val) {
console.log(attrs.ngModel, attrs.name, val)
});
ctrl.$viewChangeListeners.push(function(){
console.log('viewChange', ctrl.$viewValue)
});
},
};
}
])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<input ng-model="data.cardholder_value" name="cardholder" type="text" size="50" data-check-field />
<input ng-model="data.gender_value" name="gender" type="text" ng-required="true" data-check-field />
</div>

Getting value from ngModel in directive when using object with property

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

Resources