I am attempting to use an ng-submit call to fire a submit event to my custom directive, but it isn't firing.
Here is a plunk that illustrates my problem.
<div ng-controller="MyCtrl">
<form name="loginForm" ng-submit="login()" novalidate="">
<input type="submit" class='please-wait' value="Submit Me" />
</form>
</div>
js code:
app.directive('pleaseWait', function () {
return {
restrict: "C",
compile: function (element) {
element.on('submit', function (e) {
alert('Submit called');
});
element.on('click', function (e) {
alert('Click called');
});
}
};
});
http://plnkr.co/edit/lwHPVJI75q8bvVoSX1WP?p=preview
What am I doing wrong?
"submit" is not an event on the input element but is an event on the form so the directive is listening for an event it won't receive.
Related
I want to copy the value from vm.foo to vm.bar (that works) and then set focus to vm.bar (that does not work).
<input type="text" ng-model="vm.foo" id="foo" >
<button ng-click="vm.baa=vm.foo; angular.element('#bar').focus();"></button>
<input type="text" ng-model="vm.bar" id="bar" >
How come angular.element('#bar').focus() is not working in this situation?
Use a custom directive to emit an event.
app.directive('focusOn', () => {
return (scope, elem, attr) => {
scope.$on(attr.focusOn, (e) => {
elem[0].focus();
});
};
});
Usage:
<input type="text" ng-model="vm.foo">
<button ng-click="vm.baa=vm.foo; vm.changeFocus();"></button>
<input type="text" ng-model="vm.bar" focus-on="myFocusEvent">
and then in your controller
vm.changeFocus = () => {
$scope.$broadcast('myFocusEvent');
};
Notice that I'm using arrow functions instead of named functions
I found this Accessing Dom elements in Angular
so in our case that would be
<button ng-click="vm.baa=vm.foo; angular.element(document.querySelector('#bar')).focus();"></button>
I wonder if that fixes your problem.
Actually I would change it to
ng-click="vm.baa=vm.foo; setFocus();"
and in the controller
vm.setFocus = function() {
angular.element(document.querySelector('#bar'));
}
I am trying to edit a field and convert label into text field on click of a button and change it back to label on keypress event (ng-keypress).
I am changing the ng-show variable through controller but it is not working.
HTML:
<div ng-app>
<div ng-controller="showCrtl">
<form>
<label ng-hide="editMode" >{{field}}</label>
<input ng-show="editMode" ng-keypress="changemode($event) " ng-model="field" >
<span class="pull-right" >
<button ng-click="editMode=true" class="btn-lg btn-warning" >edit </button> </span>
</form>
</div>
</div>
JS:
function showCrtl($scope){
$scope.field="Chanel";
$scope.changemode=function(event){
if(event.charCode==13){
$scope.editMode = false;
}
}
}
My updated JS-Fiddle link: http://jsfiddle.net/8Yz7S/281/
Use ng-blur instead of ng-keypress,
<input ng-show="editMode" ng-blur="changemode() " >
DEMO
EDIT:
Use the following directive to handle the enter key event,
app.directive('ngEnter', function() {
return function(scope, element, attrs) {
element.bind("keydown keypress", function(event) {
if (event.which === 13) {
scope.$apply(function() {
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
DEMO
Can you try the below solution.
<input ng-show="editMode" ng-keypress="changemode($event) " >
Added interval to update the view
function showCrtl($scope, $timeout){
$scope.changemode=function(event){
if(event.charCode==13){
$timeout(function() {
$scope.editMode = false;
}, 500);
}
}
}
http://jsfiddle.net/gsjsfiddle/hcu5mkhm/3/
The reason its not working for you is that, you are not preventing the default behavior of Enter key. So After changemode function is executed and editmode is set to false, click event of Edit button is also getting executed, setting editmode back to true.
All you need to do is call event.preventDefault(); as shown below:
function showCrtl($scope){
$scope.field="Chanel";
$scope.changemode=function(event){
if(event.charCode==13){
$scope.editMode = false;
event.preventDefault(); // <<<<<<<
}
}
}
To verify this behavior you can check this fiddle: http://jsfiddle.net/vnathalye/8Yz7S/301/
Try it after commenting the line event.preventDefault(); and check the console.
You want to obfuscate as much logic as possible from the view. So as he suggested, use
<input ng-show="editMode" ng-keypress="changemode($event)">
Then, do all your logic inside the changemode() function:
$scope.changemode = function(evt) {
$timeout(function() {$scope.editMode = false;},100);
}
http://jsfiddle.net/8Yz7S/293/
I have a form with multiple submit buttons:
<form name="myForm" customSubmit>
<input type="text" ng-minlength="2">
<button type="submit" ng-click="foo1()"></button>
<button type="submit" ng-click="foo2()"></button>
</form>
and a directive:
angular.module('customSubmit', [])
.directive('customSubmit', function() {
return {
require: '^form',
scope: {
submit: '&'
},
link: function(scope, element, attrs, form) {
element.on('submit', function() {
scope.$apply(function() {
form.$submitted = true;
if (form.$valid) {
return scope.submit();
}
});
});
}
};
});
my goal is to submit the form only when it's valid, with multiple submit buttons (i.e. I can't use the ng-submit directive in the form). The above code doesn't work. What is the correct way to do that? Is that even possible?
I'd suggest you to use one of the simpler way of doing it. Just check your form is valid or not on ng-click & if its valid call the desired method from it.
Markup
<form name="myForm" customSubmit>
<input type="text" ng-minlength="2">
<button type="button" ng-click="myForm.$valid && foo1()"></button>
<button type="button" ng-click="myForm.$valid && foo2()"></button>
</form>
But checking myForm.$valid on each click looks bit repeating code in number of times. Rather than that you could have one method in controller scope which will validate form and call desired method for submitting form.
Markup
<form name="myForm" customSubmit>
<input type="text" ng-minlength="2">
<button type="button" ng-click="submit('foo1')"></button>
<button type="button" ng-click="submit('foo2')"></button>
</form>
Code
$scope.submit = function(methodName){
if($scope.myForm.$valid){
$scope[methodName]();
}
}
In both the cases you could make you button type to button instead
of submit
Update
To make it generic you need to put it on each button instead of putting directive on form once.
HTML
<form name="myForm">
<input type="text" name="test" ng-minlength="2" ng-model="test">
<button custom-submit type="submit" fire="foo1()">foo1</button>
<button custom-submit type="submit" fire="foo2()">foo2</button>
</form>
Code
angular.module("app", [])
.controller('Ctrl', Ctrl)
.directive('customSubmit', function() {
return {
require: '^form',
scope: {
fire: '&'
},
link: function(scope, element, attrs, form) {
element.on('click', function(e) {
scope.$apply(function() {
form.$submitted = true;
if (form.$valid) {
scope.fire()
}
});
});
}
};
});
Plunkr
The solution was to put the directive on the submit button, and use directive 'require':
<form>
<button my-form-submit="foo()"></button>
</form>
angular.module('myFormSubmit', [])
.directive('myFormSubmit', function() {
return {
require: '^form',
scope: {
callback: '&myFormSubmit'
},
link: function(scope, element, attrs, form) {
element.bind('click', function (e) {
if (form.$valid) {
scope.callback();
}
});
}
};
});
I have a form with only a text area. Is it possible to execute ng-submit when a user hits enter in the textarea? I'm able to accomplish this using ng-keyup but was wondering if there was a better solution.
<form ng-show="messages.conversation" ng-submit="messages.reply()">
<textarea class="msg-textarea" ng-model="messages.replyText"
ng-keyup="$event.keyCode == 13 ? messages.reply() : null">
</textarea>
<button type="submit" value="submit" class="btn-primary btn-sm btn-block"
ng-click="messages.reply()">Reply
</button>
</form>
#EpokK once solved the problem with the following code:
How to use a keypress event in AngularJS?
You need to add a directive, like this:
Javascript:
app.directive('ngEnter', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
scope.$apply(function (){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
HTML:
<div ng-app="" ng-controller="MainCtrl">
<input type="text" ng-enter="doSomething()">
</div>
<div ng-click="process1()" id="1">
<div ng-click="process2()" id="2">
</div>
</div>
When I click the div which id is two, it will both trigger process1 and process2,How can I just trigger process2?
You can use directive for this. It will be more generalise to stop event propagation.
HTML
<div ng-click="process1()" id="1">
<div ng-click="process2()" id="2" stop-event>
</div>
In controller:
$scope.process1 = function(){
alert(1);
}
$scope.process2 = function(){
alert(2);
}
and just use a directive
.directive('stopEvent', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
element.bind('click', function (e) {
e.stopPropagation();
});
}
}
jsFiddle: http://jsfiddle.net/6m290Lbt/3/
If you wanted, you could make this solution more generic like this answer to a different question: https://stackoverflow.com/a/14547223/347216
I think you should pass the $event from the html in the ng-click of id 2 element and then call the stopPropagation method of that event in the controller.
HTML -
<div ng-click="process1()" id="1">
<div ng-click="process2($event)" id="2">
</div>
</div>
and in the controller -:
app.controller('MainCtrl', function($scope) {
$scope.process1 = function(){
alert(1);
}
$scope.process2 = function(event){
event.stopPropagation();
alert(2);
}
});
JSFiddle - http://jsfiddle.net/SSHYK/131/
Thanks!
One solution is to use $event.stopPropagation. Also you should avoid to name elements id with numbers.
<div ng-click="process1();$event.stopPropagation();" id="div1">
event.stopPropagation:
Description: Prevents the event from bubbling up the DOM tree,
preventing any parent handlers from being notified of the event.
plunker
References
event.stopPropagation()