In my angular app, I've to use different directives on a single field.
here are my directives
angular.module('app')
.directive('focusMe', function ($timeout) {
return {
scope: { trigger: '#focusMe' },
link: function (scope, element, attr) {
scope.$watch('trigger', function (value) {
if (value === "true") {
$timeout(function () {
element[0].focus();
});
}
});
}
};
});
and another one for datepicker
.directive('ngDatepicker', function() {
return {
restrict: 'A',
replace: true,
scope: {
ngOptions: '=',
ngModel: '='
},
template: "<div class=\"input-append date\">\n <input type=\"text\"><span class=\"add-on\"><i class=\"icon-th\"></i></span>\n</div>",
link: function(scope, element) {
scope.inputHasFocus = false;
element.datepicker(scope.ngOptions).on('changeDate', function(e) {
var defaultFormat, defaultLanguage, format, language;
defaultFormat = $.fn.datepicker.defaults.format;
format = scope.ngOptions.format || defaultFormat;
defaultLanguage = $.fn.datepicker.defaults.language;
language = scope.ngOptions.language || defaultLanguage;
return scope.$apply(function() {
return scope.ngModel = $.fn.datepicker.DPGlobal.formatDate(e.date, format, language);
});
});
element.find('input').on('focus', function() {
return scope.inputHasFocus = true;
}).on('blur', function() {
return scope.inputHasFocus = false;
});
return scope.$watch('ngModel', function(newValue) {
if (!scope.inputHasFocus) {
return element.datepicker('update', newValue);
}
});
}
};
});
it throws me an error
Multiple directives asking for new/isolated scope
after hours of searching and working on different solutions, i finally understand this one same like my problem and changed my first directive like this
angular.module('app')
.directive('focusMe', function ($timeout) {
return {
link: function (scope, element, attr) {
scope.$watch(attr.focusMe, function (value) {
if (value === "true") {
$timeout(function () {
element[0].focus();
});
}
});
}
};
})
But now its not working because it always gives me value = undefined and I don't know why it is happening. May be I'm missing something here or not doing it properly??
here is my html where I'm binding its value
<input type="text" focus-me="{{ DateOfBirthFocus }}" ng-datepicker>
Any kind of help will be appreciated.
Related
I am trying to use a $scope.quickText(data) function in my controller. The function reviews the parameter 'data' and looks for any codes (ie: .smoke) and then adds that text to the value of the model.
For instance, if the ngModel value was "Completed smoke assessment" and someone types into the 'textarea' or 'text' input .smoke, it would add "patient smokes. Completed smoke assessment". This would be available to see in the view instantly as the user is typing .smoke. The function works but my directive does not.
myApp.directive('gmaEvalQuickText1', ['$timeout', function ($timeout) {
'use strict';
return {
restrict: 'A',
require: 'ngModel',
scope: {
quickTextEvaluate: '&',
},
bindToController: true,
controller: 'gmaController',
controllerAs: 'gc',
link: function ($elem, $ctrl,controller) {
$elem.on('input keyup change', function () {
var val = $elem.val().toString();
var newVal = gc.quickText(val).toString();
$ctrl.$setViewValue(newVal);
$timeout(function () {
$ctrl.$render();
});
});
}
}
}]);
I am very new to AngularJS so I am sure I am doing something wrong.
I figured out how to make it work :)
For those who need the answer:
Directive:
myApp.directive('evalQuickText', ['$timeout', function ($timeout) {
'use strict';
return {
restrict: 'A',
require: 'ngModel',
scope: {
quicktextevalfct: '='
},
link: function ($scope, $elem, attrs, $ctrl) {
$elem.on("keydown keypress", function (event) {
if(event.which === 13) {
var val = $elem.val().toString();
var newVal = $scope.quicktextevalfct(val);
$ctrl.$setViewValue(newVal + "\n");
$timeout(function () {
$ctrl.$render();
});
event.preventDefault();
}
if(event.which === 9) {
var val = $elem.val().toString();
var newVal = $scope.quicktextevalfct(val);
$ctrl.$setViewValue(newVal);
$timeout(function () {
$ctrl.$render();
});
event.preventDefault();
}
});
}
};
}]);
HTML:
eval-quick-text quicktextevalfct="quickTextEvaluate"
I have some directive for html:
<dropdown placeholder='' list='sizeWeightPriceArr' selected='selectedProductSize' property='size' value='size' style='width:60px;'></dropdown>
selectedProductSize => scope variable. Basic idea => I selected some value in dropdown and this variable in selected attribute save all changes.
JS:
.directive('dropdown', ['$rootScope', function($rootScope) {
return {
restrict: "E",
templateUrl: "templates/dropdown.html",
scope: {
placeholder: "#",
list: "=",
selected: "=",
property: "#",
value: "#"
},
link: function(scope, elem, attr) {
scope.listVisible = false;
scope.isPlaceholder = true;
scope.select = function(item) {
scope.isPlaceholder = false;
scope.selected = item[scope.value];
scope.listVisible = false;
};
scope.isSelected = function(item) {
return item[scope.value] === scope.selected;
};
scope.show = function() {
scope.listVisible = true;
};
$rootScope.$on("documentClicked", function(inner, target) {
if(!$(target[0]).is(".dropdown-display.clicked") && !$(target[0]).parents(".dropdown-display.clicked").length > 0) {
scope.$apply(function() {
scope.listVisible = false;
});
}
});
scope.$watch('selected', function(value) {
if(scope.list != undefined) {
angular.forEach(scope.list, function(objItem) {
if(objItem[scope.value] == scope.selected) {
scope.isPlaceholder = objItem[scope.property] === undefined;
scope.display = objItem[scope.property];
}
});
}
});
scope.$watch('list', function(value) {
angular.forEach(scope.list, function(objItem) {
if(objItem[scope.value] == scope.selected) {
scope.isPlaceholder = objItem[scope.property] === undefined;
scope.display = objItem[scope.property];
}
});
});
}
}
}])
dropdown.html don't irrelevant. When I make selection scope.select function run inside directive and in scope.selected = item[scope.value]; set selected value. It is working. Then in controller I try to write $scope.$watch to catch changes and run function but it won't work:
$scope.selectedProductSize = '';
$scope.$watch('selectedProductSize', function(value) {
...
});
You don't need to user $watch you can pass in the variable to the directive with two way data binding
in your controller
$scope.my_var = ''
directive html
myvar=my_var
directive
scope: {
myvar: '='
}
$scope.my_var will be bound to the directive myvar so anytime scope.myvar changes in your directive, $scope.my_var will also be updated in your controller
I am trying to use ng-click directive on a custom directive but it doesn't seem to execute the associated function defined in the controller. Looks like I am missing something very obvious. Please help. Thanks.
HTML:
<tab-link class="checked" ng-click="onEdit('performance')" href="#" value="Performance"></tab-link>
<tab-link href="#/planning" ng-click="onEdit('forecast')" value="Forecast"></tab-link>
Directive:
.directive('tabLink', function () {
return {
restrict: 'E',
template: "<a class='tab-link'><span></span></a>",
replace: true,
scope: {
text: '=',
value: '#'
},
link: function (scope, element) {
$(function () {
var span = element[0].children[0];
span.innerHTML = scope.value;
$(element[0]).on("click", function (e) {
$.each($(".tab-link"), function (index, el) {
if (el != element[0]) {
if ($(el).hasClass("checked")) {
$(el).removeClass("checked");
}
} else {
if (!$(el).hasClass("checked")) {
$(el).addClass("checked");
}
}
});
})
});
}
}
})
Controller:
$scope.onEdit = function(page) {
console.log(msg);
};
You can check the alert.
$scope.onEdit = function(page) {
alert(page);
console.log(page);
};
I have the following code snippets:
HTML:
<div data-filedrop data-ng-model="file"></div>
Controller:
$scope.$watch('file', function(newVal) {
if (newVal) {
alert("File",newVal);
}, false);
}
Directive:
angular.module('app').directive('filedrop', function () {
return {
restrict: 'A',
templateUrl: './directives/filedrop.html',
replace: true,
scope: {
ngModel: '=ngModel'
},
link: function (scope, element) {
var dropzone = element[0];
dropzone.ondragover = function () {
this.className = 'hover';
return false;
};
dropzone.ondragend = function () {
this.className = '';
return false;
};
dropzone.ondrop = function (event) {
event.preventDefault();
this.className = '';
scope.$apply(function () {
scope.ngModel = event.dataTransfer.files[0];
});
return false;
};
}
};
});
The $watch function is never triggered when I update the $scope.
Any Ideas?? Might be an isolated scope issue? It used to work until yesterday... when I had to redo
bower install && npm install
I can confirm:
dropzone.ondrop is fired
event.dataTransfer.files[0] does contain the file being dropped
because of the bower install I also tried angular 2.1.14, 2.1.15 and 2.1.16 (current) but none are working
Thanks!
Sander
ngModel is a controller/provider, it's not a scope. It's not identical to using a scope like in a controller in any way whatsoever. You have to use ngModel.$setViewValue('some value') to manipulate the value. You also have to add the ngModel like this:
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
// do some stuff
ngModel.$setViewValue(element.html()); // example
}
I found a good tutorial which describes this perfectly: http://suhairhassan.com/2013/05/01/getting-started-with-angularjs-directive.html#.U1jme-aSzQ4
Another option would of course be to just pass a scope variable like this:
Directive:
scope: {
'someAttribute': '='
},
link: function(scope, element) {
dropzone.ondrop = function(event) {
scope.$apply(function() {
scope.someAttribute = event.dataTransfer.files[0];
});
}
}
Controller View:
<div filedrop some-attribute="mymodel"></div>
Controller:
$scope.$watch('mymodel', function(newVal) {
// yeah
});
It seems that you are not modifying the value of scope.ngModel. Instead you are overwriting variable scope.ngModel so that it points to the different object, namely: event.dataTransfer.files[0]
How can I refer to directive's controller function from $apply in another directive of the same element? Example:
<myelement hint="myelement.controller.getMe()">hoverMe</myelement>
app.directive("myelement", function () {
return {
restrict: "E",
controller: function ($scope) {
this.getMe = function () {
return "me";
};
}
}
});
app.directive("hint", function () {
return {
restrict: "A",
controller: function ($rootScope) {
this.showHint = function (getMsg) {
alert($rootScope.$apply(getMsg)); //what should be written here?
}
},
link: function (scope, element, attrs, controller) {
element.bind("mouseenter", function () {
controller.showHint(attrs.hint);
});
}
}
});
Sources: http://plnkr.co/edit/9qth9N?p=preview
Use require (read more about it here).
app.directive("hint", function () {
return {
restrict: "A",
require: ["myelement", "hint"],
controller: function ($scope) {
this.showHint = function (msg) {
alert($scope.$apply(msg)); //what should be written here?
}
},
link: function (scope, element, attrs, ctrls) {
var myElementController = ctrls[0],
hintController = ctrls[1];
element.bind("mouseenter", function () {
hintController.showHint(myElementController.getMsg());
});
}
}
});
UPDATE (about making Hint universal, see comments below)
To make Hint directive universal, than you could use the $scope as the medium between them.
app.directive("myelement", function () {
return {
restrict: "E",
controller: function ($scope) {
$scope.getMe = function () {
return "me";
};
}
}
});
<myelement hint="getMe()">hoverMe</myelement>
The only change is that the getMe message is not setted in the controller (this.getMe) but in the $scope ($scope.getMe).