Disable ui-sref based on a condition - angularjs

Can you tell me a way to disable the submit button, which changes to a new state by:
<a ui-sref="state">Submit</a>
The button should be enabled only when the form is valid.
ng-disabled with ui-sref does not work:
<form name="tickets">
<button ng-disabled="!canSave()"><a ui-sref="view">Submit</a></button>
</form>
canSave function inside app.js being:
$scope.canSave = function(){
return $scope.tickets.$dirty && $scope.tickets.$valid;
};

You could simply pair it with ng-click so that ng-disabled will work.
.controller('myCtrl', function($scope, $state) {
// so that you can call `$state.go()` from your ng-click
$scope.go = $state.go.bind($state);
})
<!-- call `go()` and pass the state you want to go to -->
<button ng-disabled="!canSave()" ng-click="go('view')>Submit</button>
Here's a more fancy way using a custom directive:
angular.module('myApp', ['ui.router'])
.config(function($stateProvider) {
$stateProvider.state('home', {
url: '/'
});
})
.controller('myCtrl', function() {
})
.directive('uiSrefIf', function($compile) {
return {
scope: {
val: '#uiSrefVal',
if: '=uiSrefIf'
},
link: function($scope, $element, $attrs) {
$element.removeAttr('ui-sref-if');
$compile($element)($scope);
$scope.$watch('if', function(bool) {
if (bool) {
$element.attr('ui-sref', $scope.val);
} else {
$element.removeAttr('ui-sref');
$element.removeAttr('href');
}
$compile($element)($scope);
});
}
};
})
;
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.13/angular-ui-router.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<form name="form">
<input ng-model="foo" ng-required="true">
<button ng-disabled="form.$invalid">
<a ui-sref-if="!form.$invalid" ui-sref-val="home">test</a>
</button>
</form>
</div>

There is a pure CSS solution for the problem.
Just set the pointer-events on your a tag to none:
button[disabled] > a {
pointer-events: none;
}
Of course you should set a more accurate CSS selector to target just the buttons you want.

My take on the directive provided by #m59 (without introducing an isolated scope):
.directive('uiSrefIf', function($compile) {
return {
link: function($scope, $element, $attrs) {
var uiSrefVal = $attrs.uiSrefVal,
uiSrefIf = $attrs.uiSrefIf;
$element.removeAttr('ui-sref-if');
$element.removeAttr('ui-sref-val');
$scope.$watch(
function(){
return $scope.$eval(uiSrefIf);
},
function(bool) {
if (bool) {
$element.attr('ui-sref', uiSrefVal);
} else {
$element.removeAttr('ui-sref');
$element.removeAttr('href');
}
$compile($element)($scope);
}
);
}
};
})

The easiest way that I found to do it conditionally in the template
When your condition is met, i point it to the current state which doesn't activate the transition else I transition to the state needed.
<a ui-sref="{{ 1==1 ? '.': 'state({param:here})'}}">Disabled Link</a>

I had problems with the isolate scope and using other directives inside anchors, so here's my take, replacing the iscolate scope with regular attributes.
angular.module('app').directive('uiSrefIf', ['$compile', function($compile) {
var directive = {
restrict: 'A',
link: linker
};
return directive;
function linker(scope, elem, attrs) {
elem.removeAttr('ui-sref-if');
$compile(elem)(scope);
scope.$watch(attrs.condition, function(bool) {
if (bool) {
elem.attr('ui-sref', attrs.value);
} else {
elem.removeAttr('ui-sref');
elem.removeAttr('href');
}
$compile(elem)(scope);
});
}
}]);
Html Looks like this.
<a ui-sref-if condition="enableLink()" value="init.main">
<cover class="card-image" card="card"></cover>
</a>

ui-router v1.0.18 introduced support for ng-disabled on anchor tags.

in ui-sref you can try and hide url based on codition for example i have this code and it works in urls
<a ui-sref="category-edit({pk:category.id})" ng-show="canEdit(category.owner)" class="btn btn-primary"><i class="glyphicon glyphicon-pencil"></i></a>
and in my controller
$scope.canEdit = function(category){
return category == AuthUser.username ;
}
Authuser is a factory in my main page
<script>
// Configure the current user
var app = angular.module('myApp'); // Not including a list of dependent modules (2nd parameter to `module`) "re-opens" the module for
app.factory('AuthUser', function() {
return {
username: "{{ user.username|default:''|escapejs }}"
}
});
</script>

Related

Call function when hidden element is shown

Is it possible to call a function on the controller when a ng-show sets to true and an previous hidden element is visible? I need a directive to run a function when the element it is inside goes from hidden to visible.
<div ng-show="showOrNot" >
This is secret text.
<my-directive> I need to call a function </my-directive>
</div>
You can use ng-init to call function and use ng-if here is example:
var app = angular.module('app',[]);
app.controller('Demo',['$scope', Demo]);
function Demo($scope){
$scope.showOrNot = false;
$scope.Show = function(){
$scope.showOrNot = true;
alert("shown");
}
$scope.hello = function(){
alert("function call!");
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div ng-app="app" ng-controller="Demo">
<div ng-if="showOrNot">
<div ng-init="hello()">This is secret text.</div>
</div>
<button ng-click="Show()">click</button>
</div>
You can simply pass the showOrNot scope to your directive's scope. Then $watch it and add the desired logic after the value changes.
Simply:
<my-directive value-to-watch="showOrNot">I need to call a function</my-directive>
Then the directive:
angular.module('app').directive('myDirective', function() {
return {
restrict:'E',
scope: {
valueToWatch:'='
},
controller: function($scope) {
$scope.$watch('valueToWatch', function (newValue, oldValue) {
//Case when new value is true and old value is false
if(newValue && !oldValue) {
//Call the function you want
}
});
}
}
})
you can use $watch in your controller inorder to call a function when it is true.
<my-directive content="showOrNot"> I need to call a function </my-directive>
.directive('myDirective', function() {
return {
restrict: 'E',
scope: {
content: '=',
}
link: function (scope, element) {
scope.$watch('content', function (newvalue, oldvalue) {
if(newvalue == true)
{
//your function here
}
});
}
}
}
you can write something like this.

Removing directive attribute does not remove listener

I have a button with a ng-click attribute. If I remove the ng-click attribute, the listener persists. How can I remove the event listener when I remove the ng-click attribute?
angular.module('testApp', ['ng'])
.directive('testDir', testDir)
.controller('testCtrl', testCtrl);
function testDir() {
return {
compile: (elem, attrs) => {
// Remove ng-click attribute
elem.removeAttr('ng-click');
}
};
}
function testCtrl($scope) {
$scope.count = 0;
$scope.handleClick = function() {
$scope.count++;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="testApp">
<div ng-controller="testCtrl">
<button test-dir ng-click="handleClick()">Click Me</button>
<p>
Count: {{count}}
</p>
</div>
</div>
To remove sibling directives, re-compile the element without the sibling directives and replace the element.
angular.module('testApp').directive('testDir', function($compile) {
return {
link: (scope,elem, attrs) => {
// Remove ng-click attribute
attrs.$set('ngClick');
// Prevent infinite recursive re-compile
// Remove test-dir attribute
attrs.$set('testDir');
//Change button text
elem.text("New Click Me")
//re-compile
var newLinkFn = $compile(elem);
//replace
newLinkFn(scope, function transclude(clone) {
elem.replaceWith(clone);
});
}
};
});

Make directive function accessible in parent scope without events

I have a directive with an isolated scope and want to call its function to update data from the parent controller without using events.
var myApp = angular.module('MyApp',[]);
myApp.directive('myDirective', function() {
return {
scope: {},
link: function(scope) {
scope.update = function() {
alert('Directive updated!');
}
}
}
});
function MyCtrl($scope) {
$scope.updateDirective = function() {
// make me call update() function in directive
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="MyApp" ng-controller="MyCtrl">
<button ng-click="updateDirective()">Update!</button>
<span my-directive></span>
</div>
You could apply this solution.
In this way you are passing a variable in two way binding:
my-directive="myFunction" in the html
and myFunction: '=myDirective' in the directive)
Then assign the function in the directive:
scope.myFunction = function () {
alert('Directive updated!');
}
In this way you can use a function defined in a directive.
var myApp = angular.module('MyApp', []);
myApp.directive('myDirective', function () {
return {
scope: {
myFunction: '=myDirective'
},
link: function (scope) {
scope.myFunction = function () {
alert('Directive updated!');
}
}
}
});
function MyCtrl($scope) {
$scope.myFunction = {};
$scope.updateDirective = function () {
console.log( $scope.myFunction );
$scope.myFunction();
// make me call update() function in directive
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="MyApp" ng-controller="MyCtrl">
<button ng-click="updateDirective()">Update!</button> <span my-directive="myFunction"></span>
</div>
You could tackle this issue by introducing a new directive that is required by your isolated directive. Conveniently, you can assign the controller to this new directive.
Once required you then 'register' your isolated directive to the 'parent' directive as the target for your function. In the code snippet below I only provided a way to add 1 directive, but you could easily extend this to be an array of child directives. A good of example of such a setup are tabs, where each tab is a child directive of a common tabs directive.
angular.module("MyApp", []);
angular.module('MyApp').directive("myParentDirective", function(){
return {
controller: function ($scope) {
var childUpdate;
this.registerChild = function(_childUpdate_){
childUpdate = _childUpdate_;
};
$scope.updateDirective = function() {
childUpdate();
};
}
};
});
angular.module('MyApp').directive('myDirective', function() {
return {
require: '^myParentDirective',
scope: {},
link: function(scope, element, attrs, myParentController) {
myParentController.registerChild(update);
function update() {
alert('Directive updated!');
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="MyApp">
<div my-parent-directive>
<button ng-click="updateDirective()">Update!</button>
<span my-directive></span>
</div>
</div>

angularjs custom confirm box

So I'm trying to implement a custom confirm box using Angular. Ideally, I would simply like to add an attribute to enable the functionality. Example:
<button type="button" ng-click="delete(foo)">Delete</button> -> <button type="button" ng-click="delete(foo)" ng-confirm="Are you sure you want to delete this foo?">Delete</button>
(foo is inside an ng-repeat... foo in fooList..)
So all of the problems I am having revolve around tying the click event that would normally happen to a different button. I have a seperate directive "confirmBox" that will create my modal (not using bootstrap) and handle all of the showing/hiding/etc.
What I am currently using requires me to alter my ng-click functionality, which I really want to get away from:
Current Implementation:
<button ... ng-click="confirm('Are you sure you want to delete this foo?, 'delete', foo)">Delete</button>
var confirmModule = angular.module('confirm', []);
confirmModule.run(function($rootScope) {
$rootScope.confirm = function(text, func, obj) {
$rootScope.$broadcast('confirm', func, obj, text);
};
});
confirmModule.directive('confirmBox', function($parse) {
return {
restrict: 'A',
template: myModalTemplate,
link: function(scope, element, attrs){
element.hide();
var noBtn = element.find("[name='no']");
noBtn.bind("click", function() {
element.hide();
});
scope.$on("confirm", function(event, func, obj, text) {
var yesBtn = element.find("[name='yes']");
element.show();
yesBtn.unbind("click").bind("click", function() {
scope[func](obj);
});
});
}
}
});
Anyone have any ideas? I started by adding the directive for the button and then unbinding the click event so ng-click doesn't fire. Then I am left with the string 'delete(foo)' from the ng-click attribute that I can execute with $parse(attrs.ngClick)(scope), but I don't know how to tie that to the separate directives button click.
Edit: Here is a fiddle with my current attempt at implementation. The problem is the variable being passed in to the function is always undefined.
http://jsfiddle.net/UCtbj/2/
Edit2: Updated implementation, however I don't particularly like how it links the two directives together by targetting the other directives elements.
http://jsfiddle.net/UCtbj/3/
It seems to me that you're trying to do things the jQuery way from within the directive. However, what you want is as simple as pulling in the UI-Bootstrap directive for confirming actions. http://plnkr.co/edit/JhfAF1?p=preview
First simple service for modal windows:
app.service('ConfirmService', function($modal) {
var service = {};
service.open = function (text, onOk) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalConfirmCtrl',
resolve: {
text: function () {
return text;
}
}
});
modalInstance.result.then(function (selectedItem) {
onOk();
}, function () {
});
};
return service;
})
app.controller('ModalConfirmCtrl', function ($scope, $modalInstance, text) {
$scope.text = text;
$scope.ok = function () {
$modalInstance.close(true);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
Then simple directive that uses it:
app.directive('confirm', function(ConfirmService) {
return {
restrict: 'A',
scope: {
eventHandler: '&ngClick'
},
link: function(scope, element, attrs){
element.unbind("click");
element.bind("click", function(e) {
ConfirmService.open(attrs.confirm, scope.eventHandler);
});
}
}
});
And here u go:
<button ng-click="test(12)" confirm='Are you sure?'>Button</button>
http://plnkr.co/edit/LOZOnsVyx3JU5XoKYn74?p=preview
To allow a button to be marked up like
<button type="button" ng-click="deleteItem(drink)" ng-confirm="Are you sure you want to delete '{{drink.name}}'">Delete</button>
You can write a directive that
Intercepts the click event before ngClick's click handler can run
Opens a dialog (using $modal and not the removed $dialog)
On close of the dialog (which is treated as a success) run the function specified by the ngClick attribute on the element.
Basing the code on the previous answer, you can do this as follows:
app.directive('ngConfirm', function($modal, $parse) {
return {
// So the link function is run before ngClick's, which has priority 0
priority: -1,
link: function(scope, element, attrs) {
element.on('click', function(e) {
// Don't run ngClick's handler
e.stopImmediatePropagation();
$modal.open({
templateUrl: 'ng-confirm-template',
controller: 'ngConfirmController',
resolve: {
message: function() {
return attrs.ngConfirm;
}
}
}).result.then(function() {
// Pass original click as '$event', just like ngClick
$parse(attrs.ngClick)(scope, {$event: e});
});
});
}
};
});
which needs a simple controller:
app.controller('ngConfirmController', function($scope, $modalInstance, message) {
$scope.message = message;
$scope.yes = function() {
$modalInstance.close();
};
$scope.no = function() {
$modalInstance.dismiss();
};
});
and template for the dialog:
<script type="text/ng-template" id="ng-confirm-template">
<div class="modal-body">
<p>{{message}}</p>
</div>
<div class="modal-footer">
<button class="btn btn-link pull-left" ng-click="no()">No</button>
<button class="btn btn-primary pull-right" ng-click="yes()">Yes</button>
</div>
</script>
You can see this running at http://plnkr.co/edit/Gm9lFsGb099w6kCMQoVY?p=preview
Edit: changed plunker link to example without scrollbar appearing/disappearing on display of the dialog
Here is a nice directive for that.That is ngBootbox. Check it out.
<button class="btn btn-lg btn-primary"
ng-bootbox-title="A cool title!"
ng-bootbox-custom-dialog="Some custom text"
ng-bootbox-buttons="customDialogButtons"
ng-bootbox-class-name="some-class">
Custom dialog
</button>
<script>
$scope.customDialogButtons = {
warning: {
label: "Warning!",
className: "btn-warning",
callback: function() { $scope.addAction('Warning', false); }
},
success: {
label: "Success!",
className: "btn-success",
callback: function() { $scope.addAction('Success!', true) }
},
danger: {
label: "Danger!",
className: "btn-danger",
callback: function() { $scope.addAction('Danger!', false) }
},
main: {
label: "Click ME!",
className: "btn-primary",
callback: function() { $scope.addAction('Main...!', true) }
}
};
</script>
Demo
ngBootbox
I created a repo for this functionality. It wraps the ui-bootstrap modal to produce a confirmation box. It is customizable and easily integrated into any application.
Here is the link to the GitHub: https://github.com/Schlogen/angular-confirm
Example Usages:
As a directive:
<button type="button" ng-click="delete()" confirm-if="checked" confirm="Are you sure, {{name}}?">Delete</button>
As a service:
$confirm({text: 'Are you sure you want to delete?'})
.then(function() {
$scope.deletedConfirm = 'Deleted';
});
Ok, here is the one I ended up going with
1) Create a service for the dialog
app.service('dialogModal', [
'$modal', function($modal) {
return function(message, title, okButton, cancelButton) {
okButton = okButton === false ? false : (okButton || 'Yes');
cancelButton = cancelButton === false ? false : (cancelButton || 'No');
var modalInstance = $modal.open({
templateUrl: '/templates/deletePrompt.html',
controller: ModalInstanceCtrl,
resolve: {
settings: function() {
return {
modalTitle: title,
modalBody: message,
okButton: okButton,
cancelButton: cancelButton
};
}
}
});
// return the modal instance
return modalInstance;
}
}
]);
2) Create a controller and pass the model instance in it
var ModalInstanceCtrl = function ($scope, $modalInstance, settings) {
angular.extend($scope, settings);
$scope.ok = function () {
$modalInstance.close(true);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
3) included the link into the header to take on default styling
<link data-require="bootstrap-css#3.x" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
4) overwrote the styling in my own css
5) Here is my delete prompt template
<div id="overlayClearMainDiv" class="dialog-modal">
<div id="overlayClearText">
<span>{{modalBody}}</span>
</div>
<div id="overlayClearButton">
<button id="overlayClearYesButton" class="confirmButton" type="button" ng-click="ok()" ng-show="okButton">{{okButton}}</button>
<button class="confirmButton-white" ng-click="cancel()" ng-show="cancelButton">{{cancelButton}}</button>
</div>
</div>
Here's a quick one for you - http://plnkr.co/edit/YklthDZcknmvMjU5A6pe?p=preview
So basically if you are interested in showing a modal dialog once a user clicks on let's say, a button there's no need to make it difficult.
All you need is a simple directive that encapsulate $modal service found in ui-bootstrap.
In my simple example I just pass in a string representing a message and then defining a on-confirm attribute that my directive invokes once the user confirms. Invoking the function itself leverages the awesomeness of $parse to resolve the expression and once resolved, invoke it with the scope.
Nice and clear and here's how it looks like.
View
<body ng-controller="AppController">
<input type="button" value="Delete"
confirm="'Are you sure you want to delete me?'" on-confirm="delete()" />
<script type="text/ng-template" id="modal.html">
<div class="modal-header">
<h3 class="modal-title">Confirm</h3>
</div>
<div class="modal-body">
<p>The world won't be a better place if you delete me.</p>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
</body>
Controller / Directive
angular
.module('App', ['ui.bootstrap'])
.controller('AppController', ['$scope', function($scope){
$scope.delete = function(){
alert('Woho, Im deleted!');
};
}])
.directive('confirm', ['$modal', '$parse', function($modal, $parse){
return {
link: function(scope, el, attr){
el.bind('click', function(){
var instance = $modal.open({
templateUrl: 'modal.html',
controller: ['$scope', '$modalInstance', modalController]
});
instance.result.then(function(){
// close - action!
$parse(attr.onConfirm)(scope);
},function(){
// dimisss - do nothing
});
});
}
};
function modalController(modalScope, $modalInstance){
modalScope.ok = function(){
modalInstance.close();
};
modalScope.cancel = function(){
modalInstance.dismiss();
};
}
}]);

Input autofocus attribute

I have places in my code where I have this:
<input data-ng-disabled="SOME_SCOPE_VARIABLE" />
I would like to be able to use it like this too:
<input data-ng-autofocus="SOME_SCOPE_VARIABLE" />
Or even better, mimicking how ng-style is done:
<input data-ng-attribute="{autofocus: SOME_SCOPE_VARIABLE}" />
Does this exist in the current version of AngularJS? I noticed in the code there's a BOOLEAN_ATTR which gets all the attr's that AngularJS supports. I don't want to modify that in fear of changing versions and forgetting to update.
Update: AngularJS now has an ngFocus directive that evaluates an expression on focus, but I mention it here for the sake of completeness.
The current version of AngularJS doesn't have a focus directive, but it's in the roadmap. Coincidentally, we were talking about this on the mailing list yesterday, and I came up with this:
angular.module('ng').directive('ngFocus', function($timeout) {
return {
link: function ( scope, element, attrs ) {
scope.$watch( attrs.ngFocus, function ( val ) {
if ( angular.isDefined( val ) && val ) {
$timeout( function () { element[0].focus(); } );
}
}, true);
element.bind('blur', function () {
if ( angular.isDefined( attrs.ngFocusLost ) ) {
scope.$apply( attrs.ngFocusLost );
}
});
}
};
});
Which works off a scope variable as you requested:
<input type="text" ng-focus="isFocused" ng-focus-lost="loseFocus()">
Here's a fiddle: http://jsfiddle.net/ANfJZ/39/
You can do this with the built-in ngAttr attribute bindings.
<input ng-attr-autofocus="{{SOME_SCOPE_VARIABLE}}">
The autofocus attribute will be added if SOME_SCOPE_VARIABLE is defined (even if it's false), and will be removed if it's undefined. So I force falsy values to be undefined.
$scope.SOME_SCOPE_VARIABLE = someVar || undefined;
This directive should do the trick:
angular.module('utils.autofocus', [])
.directive('autofocus', ['$timeout', function($timeout) {
return {
restrict: 'A',
scope: {'autofocus':'='}
link : function($scope, $element) {
$scope.$watch 'autofocus', function(focus){
if(focus){
$timeout(function() {
$element[0].focus();
});
}
}
}
}
}]);
Taken from here: https://gist.github.com/mlynch/dd407b93ed288d499778
scope.doFocus = function () {
$timeout(function () {
document.getElementById('you_input_id').focus();
});
};
Create a directive like this
.directive('autoFocus', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function ($scope, $element) {
$timeout(function () {
$element[0].focus();
});
}
}
<input type="text" auto-focus class="form-control msd-elastic" placeholder="">
What I did is using regular autofocus on my inputs: <input autofocus>
And then I set the focus on the first visible input with autofocus when angular is ready:
angular.element(document).ready(function() {
$('input[autofocus]:visible:first').focus();
});
Hope this helps.
I did it with two custom directives, something like this:
(function(angular) {
'use strict';
/* #ngInject */
function myAutoFocus($timeout) {
return {
restrict: 'A',
link: function(scope, element) {
$timeout(function() {
element[0].focus();
}, 300);
}
};
}
function myFocusable() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var focusMethodName = attrs.myFocusable;
scope[focusMethodName] = function() {
element[0].focus();
};
}
};
}
angular
.module('myFocusUtils', [])
.directive('myAutoFocus', myAutoFocus)
.directive('myFocusable', myFocusable);
}(angular));
If you add attribute my-auto-focus to an element, it will receive focus after 300ms. I set the value to 300 instead of 0 to let other async components to load before setting the focus.
The attribute my-focusable will create a function in the current scope. This function will set focus to the element when called. As it creates something in the scope, be cautious to avoid overriding something.
This way you don't need to add something to Angular's digest cycle (watch) and can do it entirely in the view:
<input my-focusable="focusOnInput"></input>
<button ng-click="focusOnInput()">Click to focus</button>
I created a JSFiddle to show the myFocusable directive: http://jsfiddle.net/8shLj3jc/
For some reason I don't know, the myAutoFocus directive does not work in JSFiddle, but it works in my page.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="namesCtrl">
<div ng-repeat="x in names">
<input ng-attr-focus={{$first}} value="{{x.name + ', ' + x.country }}" />
</div>
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('namesCtrl', function($scope) {
$scope.names = [
{name:'x1',country:'y1'},
{name:'x2',country:'y2'},
{name:'x3',country:'y3'}
];
});
myApp.directive("focus", function(){
return {
restrict: "A",
link: function link(scope, element, attrs) {
if(JSON.parse(attrs.focus)){
element[0].focus();
}
}
};
});
</script>
</body>
</html>
had created above custom directive for one of my use case.
always focusses on first input element.
works for ajax data, browser back/forward buttons.
Tested on chrome and firefox(default autofocus is not supported here)
JSON.parse is used to parse string "true" returned from html to boolean true in JS.
another way to use attrs.focus === "true" for if condition.
so without $timeout you can also use auto focus like this -
<input type="text" ng-show="{{condition}}" class='input-class'></input>
angular.element(document).ready(function(){
angular.element('.input-class')[0].focus();
});
Combining whar others mentioned above:
JS Code:
myApp.directive('ngAutofocus', ['$timeout', function ($timeout) {
var linker = function ($scope, element, attrs) {
$scope.$watch('pageLoaded', function (pageLoaded) {
if (pageLoaded) {
$timeout(function () {
element[0].focus();
});
}
});
};
return {
restrict: 'A',
link: linker
};
}]);
HTML:
<input type="text" ng-model="myField" class="input-block-level edit-item" ng-autofocus>
Set pageLoaded to true from your initial load method of the page get:
var loadData = function () {
..
return $http.get(url).then(function (requestResponse) {
$scope.pageLoaded = true;
......
}

Resources