My directive has
link: function ($scope, $elm, $attrs) {
var status = $scope.item.status
if (status) {
var statusName = status.name,
item = $scope.item;
if (statusName === 'USED') {
$attrs.$set('ng-disabled', true); // this doesn't work
} else {
$elm.attr('ng-disabled', false);
}
}
}
So, my question is:
How to apply ng-disabled to element with this directive?
if (statusName === 'USED') {
$attrs.$set('disabled', 'disabled');
} else {
$elm.removeAttr('disabled');
}
Why invoke ng-disable at all? You're already once evaluating the condition yourself, so having ng-disable evaluating it again is redundant.
You would set ng-disabled to a scope variable, ex:
<input ng-disabled="isDisabled" />
And then inside your directive you can set that variable:
$scope.isDisabled = true;
//html
<div ng-app="miniapp" ng-controller="MainCtrl">
<input type="submit" mydir>
</div>
//js
'use strict';
var app = angular.module('miniapp', []);
app.directive('mydir', function ($compile) {
return {
priority:1001, // compiles first
terminal:true, // prevent lower priority directives to compile after it
compile: function(el) {
el.removeAttr('mydir'); // necessary to avoid infinite compile loop
return function(scope){
var status = scope.item.status
if (status === 'USED') {
el.attr('ng-disabled',true);
} else {
el.attr('ng-disabled',false);
}
var fn = $compile(el);
fn(scope);
};
}
};
});
app.controller('MainCtrl', function ($scope) {
$scope.item = {};
$scope.item.status = 'USED';
});
credit to Ilan Frumer
Related
var app = angular.module('myApp', []);
app.controller('checkCtrl', ['$scope','sharedService', function($scope, sharedService) {
$scope.isCutScore = function() {
if($scope.cc) {
alert('Checked');
$scope.val = true;
} else {
alert('Unchecked');
}
};
}]);
app.controller('divCtrl', ['$scope', 'sharedService', function($scope, sharedService) {
$scope.addClass = function() {
if(flag == true) {
return EL;
} else {
return EP;
}
};
}]);
app.service('sharedService', function() {
var flag = false;
if(angular.element('#cutScoreCheck').is(':checked')) {
flag = true;
} else {
flag = false;
}
});
Add and remove class to a div using ng-class on click of checkbox. But challenge is checkbox and div to which we need to apply and remove class are in different controllers. And compulsion here is to use a service which is shared by both the controllers.
In the following example if we check the checkbox, 'EL' class should be applied and if we uncheck the box, this class will be removed and 'EP' should be applied.
Code
you can use this. Works here.
I have added function to service, it will be called when user check the checkbox and I used $rootScope to reach AddClass method in different controller.
your body html
<body ng-app="myApp">
<div class="row">
<div class="col-sm-4 checkDiv" ng-controller="checkCtrl">
<input type="checkbox" id="cutScoreCheck" ng-model="cc" ng-change="checkDiv()"/>
</div>
</div>
<div class="row">
<div class="col-sm-4 container" ng-controller="divCtrl" ng-class="flag ? 'EL' : 'EP'">500</div>
</div>
<script src="CtrlCheck.js"></script>
</body>
Js part:
var app = angular.module('myApp', []);
app.controller('checkCtrl', ['$scope','sharedService', '$rootScope',function($scope, sharedService,$rootScope) {
$scope.checkDiv = function(){
var flag = sharedService.CheckDiv($scope.cc);
$rootScope.addClass(flag);
}
}]);
app.controller('divCtrl', ['$scope', 'sharedService', '$rootScope',function($scope, sharedService,$rootScope,$apply) {
$scope.flag = false;
$rootScope.addClass = function(flag) {
if(flag == 'true') {
$scope.divClass = "EL";
} else {
$scope.divClass = "EP";
}
console.log(flag)
$scope.flag = flag;
};
}]);
app.service('sharedService', function() {
var flag = false;
this.CheckDiv = function (isChecked) {
if(isChecked) {
flag = true;
} else {
flag = false;
}
return flag;
}
});
Here's a plunkr with my problem: http://plnkr.co/edit/Sx830ekQyP7YBqmRB4Nd?p=preview
Click "Open", then click on "5". Notice how it changes to "test"? Now, type something into Body. It'll either say "Say a little more..." or "Now for the title". Either way, click the button again, and notice how it doesn't change to "test"? Why not? If I remove the directive, the button changes to "test" with or without text in the body.
I know this has to do with the scope in the directive, but I don't understand what exactly is wrong. Can you explain? Thanks.
angular.module('plunker', ['ngDialog']).controller('MainCtrl', function($scope, ngDialog) {
//$scope.submitPostValue = "OK";
$scope.submitPost = function() {
$scope.submitPostValue = 'test';
};
$scope.open = function () {
console.log('open');
$scope.submitPostValue = '5';
ngDialog.openConfirm({
template: 'postModal',
showClose: true,
trapFocus: false,
scope: $scope,
}).then(function (success) {
}, function (error) {
});
};
}).directive('bodyValidator', function () {
return {
require: 'ngModel',
link: function (scope, element, attr, ctrl) {
function customValidator(ngModelValue) {
if(ngModelValue.length > 0){
if(ngModelValue.length < 10) {
scope.submitPostValue = "Say a little more...";
scope.bodyValid = false;
}
else {
scope.bodyValid = true;
if(scope.titleValid)
scope.submitPostValue = "Submit";
else
scope.submitPostValue = "Now for the title..."
}
}
else {
scope.submitPostValue = "Enter a body...";
scope.bodyValid = false;
}
return ngModelValue;
}
ctrl.$parsers.push(customValidator);
}
};
});
Try to wrap all your variables into an object.
Define $scope.obj = {}; first and change all your scope.submitPostValue to $scope.obj.submitPostValue. In your HTML, change ng-value='submitPostValue' to ng-value=obj.submitPostValue.
I'm trying to insert HTML into my div (bottom of code). I've dealt with an issue like this before so I added a filter. However, when the div is made visible through a toggle function the HTML doesn't display from the service. I have verified that the service is returning the proper HTML code.
The div is unhidden but no html is displayed.
Angular Code:
var myApp = angular.module('myApp', []);
angular.module('myApp').filter('unsafe', function ($sce) {
return function (val) {
if ((typeof val == 'string' || val instanceof String)) {
return $sce.trustAsHtml(val);
}
};
});
myApp.controller('myAppController', function ($scope, $http) {
...
SERVICE CODE
...
$scope.toggleHTMLResults();
$scope.HTMLjson = obj[0].HTML;
HTML Code:
<div id="returnedHTML" ng-bind-html="HTMLjson | unsafe " ng-hide="HTMLResults">NOT HIDDEN</div>
I'm not sure why this isn't working.
Here is my Plunker
There were multiple things wrong with your example.
Main Javascript file declared twice, first in header and second before close on body tag
You call a function as HTMLAPI() instead of $scope.HTMLAPI()
Your $scope.HTMLAPI() function was also being called before it was initialised
Fixed controller code:
app.controller('myAppCTRL', ['$scope', '$http', function ($scope, $http) {
var API = this;
$scope.HTMLInput = true;
$scope.HTMLResults = true;
$scope.toggleHTMLInput = function () {
$scope.HTMLInput = $scope.HTMLInput === false ? true : false;
}
$scope.toggleHTMLResults = function () {
$scope.HTMLResults = $scope.HTMLResults === false ? true : false;
}
$scope.HTMLAPI = function (HTML) {
var newJSON = ["[{\"ConditionId\":1111,\"ConditionDescription\":\"<i>DATA GOES HERE</i>\",\"ErrorId\":0,\"DisplayId\":0,\"DisplayName\":\"\",\"ErrorValue\":\"\"}]"];
var obj = JSON.parse(newJSON);
$scope.HTMLjson = obj[0].ConditionDescription;
$scope.toggleHTMLResults();
console.log($scope.HTMLjson);
}
$scope.HTMLAPI();
}]);
Working Example
I have a template file, a directives and a unitest file.
In template,
<span class="icon-fire"
ng-click="abcClick()" ng-show="valueChanged"></span>
In directive,
function abcDirective() {
return {
restrict: "AE",
replace: "true",
templateUrl: "abc.template.html",
scope: { valueChanged: "=" },
controller: abcController
};
}
In controller,we have a function for change value at expand.
var abcController = [
"$scope", "$rootScope", "$timeout", function ($scope, $rootScope, $timeout) {
$scope.abcClick = function () {
if ($scope.valueChanged) {
$scope.valueChanged= false;
washClothes();
} else {
$scope.valueChanged= true;
CleanHouse();
}
};
In unitest, I want to click abcClick() and it'll be change expand value by controller. But the result it's not my expect.
it("should call abcClick function and set expand is true", function () {
var $scope = $rootScope.$new();
$scope.valueChanged= true;
var htmlDirectiveWithArgument = '<change-value-button valueChanged="{{valueChanged}}">" + "</change-value-button>';
var element = $compile(htmlDirectiveWithArgument)($scope);
$scope.$digest();
var queryResult = element[0].querySelector(".icon-fire");
var wrappedQueryResult = angular.element(queryResult);
wrappedQueryResult.triggerHandler("click");
var isolatedScope = element.isolateScope();
var abcResult = isolatedScope.valueChanged;
expect(false).toEqual(abcResult);
});
abcResult is true. But I expect it'll become false. Because after we call click, It must be change valueChanged to false. because we input $scope.valueChanged= true; before we call click function.
I need to change the caret position of an input, where a given number of digits is added (Example).
app.controller('MainCtrl', function($scope, $element, $timeout, $filter) {
//$scope.val = '12';
$scope.$watch('val', function(newValue, oldValue) {
if (!isNaN(newValue)) {
if (newValue.length > 3) {
//Set Caret Position
}
}
});
});
Is it possible to do something like this example?
I need for example :
Input: 1234.
so the caret position will be 2.
New digit: 9
final: 12934
Thanks in advance.
I think that such kind of things look better in directives. For example:
app.directive('caret', function() {
function setCaretPosition(elem, caretPos) {
if (elem !== null) {
if (elem.createTextRange) {
var range = elem.createTextRange();
range.move('character', caretPos);
range.select();
} else {
if (elem.setSelectionRange) {
elem.focus();
elem.setSelectionRange(caretPos, caretPos);
} else
elem.focus();
}
}
}
return {
scope: {value: '=ngModel'},
link: function(scope, element, attrs) {
var caret = Number(attrs.caret);
scope.$watch('value', function(newValue, oldValue) {
if (newValue && newValue != oldValue && !isNaN(newValue) && newValue.length > (caret + 1)) {
setCaretPosition(element[0], caret);
}
});
}
};
});
Usage:
<input ng-model='val' caret="2" />
I used setCaretPosition function for cross browser cursor positioning from this answer.
Demo: http://plnkr.co/edit/5RSgzvyd8YOTaXPsYr8A?p=preview
I think that the best approach for this is to make a reusable directive as we are dealing with DOM manipulation.
Link to the demo: http://plnkr.co/edit/qlGi64VO1AOrNpxoKA68?p=preview
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function($scope, $element, $timeout, $filter) {
$scope.$watch('val', function(newValue, oldValue) {
if (!isNaN(newValue)) {
if (newValue.length > 3) {
// $element.find('input')[0].selectionEnd = 2;
}
}
});
});
app.directive('setCaret', function() {
return {
restrict: 'A',
link: function(scope,element,attrs) {
var changed = false;
element.bind('keypress', function() {
if(element[0].selectionStart > 3 && !changed) {
changed = true;
element[0].selectionEnd = parseInt(attrs.position, 10);
}
})
},
}
})
You can see in the commented out part in the controller we can have access to this by using $element, but as this is DOM and controllers are not for DOM manipulation we need to make this into a directive.
I also had the same problem.
I thought to solve it creating an appropriate directive. You can find it here. Enjoy it!
Usage
Include directive, declare it by caret-aware attribute
<script src="https://cdn.rawgit.com/leodido/ng-caret-aware/master/caretaware.min.js"></script>
<script type="text/javascript">
var app = angular.module('myModule', ['leodido.caretAware']);
</script>
...
<div data-ng-app="app">
<input type="text" name="myname" caret-aware="cursor"/>
</div>
Then on the scope you'll have a variable cursor containing the position of the caret in the input named myname.
Nevertheless, this directive's controller exposes an API
getPosition
setPosition
For other usage examples see example directory of the above linked github repository.
I believe you could do it by using .setSelectionRange() on your input. I updated your example - see if this is what you wanted: http://plnkr.co/edit/bIJAPPAzkzqLIDUxVlIy?p=preview
Note: setSelectionRange is not supported by IE8 (see https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement.setSelectionRange), so if you need to support IE < 9, you'll need to look for shims.
I jsfiddled a working solution.
So basically, you have to create a directive :
app.directive('keypressdetector', function($compile){
return {
restrict:'AEC',
link: function(scope, element, attrs){
element.bind("keypress", function (event) {
if(event.which === 13) {
var selectionStart = element[0].selectionStart;
var value = element.val();
var valueLength = value.length;
var newValue= '';
if (selectionStart == valueLength){
newValue = value;
} else {
newValue = value.substring(selectionStart, valueLength);
}
var newElement = angular.element('<input type="text" value="' + newValue +'"/>')
angular.element(document.body).append(newElement);
}
});
}
};
});
Your controller would be useless in that situation.
You can invoke the directive like this (see : keypressdetector) :
<div ng-app="myapp">
<div ng-controller="LoginController">
<div>Hello {{ user.firstName }}</div>
<input ng-model="user.firstName" keypressdetector />
<input type="submit" ng-click="login()" value="Login"/>
<div ng-repeat="login in logins">{{ login }}</div>
</div>
</div>
See demo : https://jsfiddle.net/Lt7aP/3468/