In my controller I want to invoke an action (say on Tab press) only when form is valid. Also I need to clear form as soon as form gets submitted succesfully. I have something like this
app.controller('CommentFormController', function($scope) {
$scope.submit = function() {
if($scope.commentForm.$valid) {
// submit form
$scope.comment = '';
$scope.commentForm.$setPristine();
}
}
});
I'd like to test this, but it looks like I have to create this $scope.contactForm by hand and stub out $setPristine() function.
Is there any other way to test it? I mean can I somehow get instance of underlying FormController in my test?
How do you handle such cases?
Setting the form to pristine will affect the state of the form but won't reset the form to your defaults values (if you've provided them). Instead you can use the DOM element method reset().
Something like this:
document.getElementById("yourform").reset();
or, since angularJS and jQuery play nicely, you can use css selectors (especially useful if you have multiple forms you want to clear at once.
So something like:
$("#yourform")[0].reset();
There are pure javascript ways to do it also:
http://www.javascript-coder.com/javascript-form/javascript-reset-form.phtml
--- So in summary, you don't need to use specific methods to do this, simply use the DOM methods, jQuery, or pure javascript. Google will probably come out with a way to do this soon. Hope this helps.
#grafthez I got same problem when try validate the form is valid in my controller by $scope.myForm.$valid.
I found a solution on https://stackoverflow.com/a/17129354. You can try to inject $compile then $compile(yourFormTemplate)($scope).
Related
I've written some custom validation code when filling out a form, but need to set the $timeout to > 100 ms in order to get it to work, and I'm curious to find out why.
The required form elements follow this format. I add the "novalidate" class if the input is wrong: (Observe, there's a ton of these elements in the form)
<div class="dottedWrapper" ng-class="{novalidate:(newController.jobDescription.length == 0) && newController.formSubmitted}">
When submitting the form, I check if any elements has the "novalidate" class and return.
self.formSubmitted = true;
$timeout(function () {
// Validate!
if (document.getElementsByClassName("novalidate").length > 0) {
return;
}
...
}, 100); // MUST SET AT LEAST 100ms for it to work in safari
However, this only works if I set the time to about over 100ms in Safari. In chrome, It's only necessary to set it to 1ms.
Correct me if I'm wrong, but here's my thinking, and bare in mind that I'm a newbie in angular:
I set the "self.formSubmitted = true;" in the beginning. This causes, through the two-way data binding an update on all the divs, since the "formSubmitted" is contained inside the ng-class.
This is done through a digest loop, which means I cannot run the "document.getElementsByClassName("novalidate")" directly after since the digest loop most run through once and update everything.
So... I use the $timeout, thinking it will let the current digest loop run, and then jump on the next digest loop. At this point, all elements should be updated.
You're breaking the MVC pattern. Don't - it's bad practice.
Why don't you just do:
if (self.jobDescription.length == 0 && self.formSubmitted)
return;
Aside from Pixelbits answer (which I totally agree with), you could try replacing $timeout with one of the following;
$evalAsync
$$postDigest
Where the former will trigger a new $digest loop (just like $timeout), and the latter will not.
Even so, I think your best bet would be to harness the built-in input validation directives. And instead of checking for the existence of a novalidate class in the DOM, just check the <form>.$valid property (<form> gets exposed on your $scope, when given a name attribute).
Your view would look something like so;
<form name="myForm">
<input ng-model="formData.jobDescription" ng-minlength="1">
</form>
And then in your controller;
// var form = $scope.myForm;
console.log(form.$valid); // true|false
Now, the above suggestion may not work for your use case - We need to see more of your implementation to be able to assist you to a greater extent.
I am trying to find the event DOM target when there are nested jQuery calls. If there was only one level of call, then event.target would get the DOM target and I could go from there. But how to get through nested calls?
I am testing with a Javascript function
jQuery(document).bind('gform_post_render', function(event, formID){
jQuery("#id").val(event.target.nodeName);
});
I can look at event.target.nodeName and see that it is "#document". I assume that is because the trigger which called this function was something like
jQuery(document).trigger('gform_post_render', ...);
And I think there is another level or two of calls above that.
What I'd like to be able to do is something like
event.trigger.event.trigger.closest(.classname).attr("attname");
although I realize that 'event.target.event.target' is not allowed.
Is there any way to do this?
BTW, what I am trying to do is extract a piece of data from the HTML that is going though a couple of WordPress plugins (popup and gravity forms) that do the jQuery calls. So I have no ability to change things, just trying to deal with what they did.
You can pass a data argument to trigger, and then access it within the handler. So you pass it like this:
$(document).trigger('gform_post_render', {target: event.target});
and then in the handler:
$(document).on('gform_post_render', function(event, data) {
var target = data.target;
...
});
I'm working with a 3rd party product where I am extending the UI with my own custom functionality. Within part of that I need to call an event after the UI has been updated with an AJAX call. Luckily the app fires a call to a Custom Event using the Prototype JS library after the call is complete, like this:
$(document.body).fire("ns:customevent");
If I add my own custom event with the same name then this works as expected
$(document).observe("ns:customevent", function(event) {
//do custom stuff here
});
[I could not get $(document.body).observe() to work here but I don't think that really matters.]
My concern here is that there may be other parts of the app that have registered functions against that event, and I am (blindly) overwriting them with my own, which will lead to issues further down the line.
Does Prototype append custom functions even though they have the same name or does it in fact overwrite them? If it does overwrite them then how can I append my function to anything that is already existing? Is there anyway of viewing what
I would imagine something like this, but I hardly know Protoype and my JS is very rusty these days.
var ExistingCustomEvent = $(document.body).Events["ns:customevent"];
$(document).observe("ns:customevent", function(event) {
ExistingCustomEvent();
//do custom stuff here
});
I can't add my event handler or add in code to call my own function, I want to try avoiding the 3rd party library (if that would even be possible).
Thanks.
As an FYI for anyone else that stumbles upon this question, following the comment from Pointy it turns out that Prototype does append the functions to the custom event.
I verified this by trying the following and both alerts fired.
$(document).observe("ns:customevent", function(event) {
alert("ALERT 1");
});
$(document).observe("ns:customevent", function(event) {
alert("ALERT 2");
});
Great :)
I have a template that looks like this:
<p ng-repeat="item in myobj.items" class="toAnimate">{{item}}</p>
and I would like to use the animate module do a jQueryUI addClass/removeClass animation on the element using the JavaScript method described in the docs:
ngModule.animation('.toAnimate', function() {
return {
enter: function(element) {
element.addClass('pulse').removeClass('pulse', 2000);
}
};
});
This works beautifully, but the problem is that, since I want to use the p.toAnimate element to display status messages, it will not change the content according to angular.
To break it down a little further, say I have a name field. When I click Save the message Name was saved successfully. is displayed. Now if I modify the name and click save again, assuming the save was successful, the message should be re-displayed to give the user feedback of the newly edited name. The pulse does not happen, however, because the items in myobj.items didn't technically change.
I realize that I could remove the item after a period of time (and that is probably the route I will take to implement the real solution), but I'm still interested to see if this sort of thing can be done using AngularJS.
What I want to do is register with angular that the message should be treated as new even though it is not. Is there any way to do this?
A fiddle to go along with this: http://jsfiddle.net/Jw3AT/
UPDATE
There is a problem with the $scope.$$phase approach in my answer, so I'm still looking for the "right" way to do this. Basically, $scope.$$phase is always returning $digest, which causes the conditional to fail. Removing the conditional gives the correct result in the interface, but throws a $rootScope:inprog.
One solution I found is to add a $apply in the middle of the controller function:
$scope.updateThingy = function () {
$scope.myobj.items = [];
if (!$scope.$$phase) {
$scope.$apply();
}
$scope.myobj.items = ['Your name was updated.'];
};
Updated fiddle: http://jsfiddle.net/744Rv/
May not be the best way, but it's an answer.
I'm working on a project in JavaScript where we're building a Greasemonkey plugin to an organizational site we're using in our office. We're having trouble getting our changes to stay rendered, since we can't simply inject our changes into the existing render function.
As a result, we need to find every event where rendering happens and inject our own render function there. However, there are some events that we can see happening, but we can't hook into them. What I'd like to know is how to bind a function to an object's data member, so that the function is called whenever that member changes. One of our team members seemed to think it was possible, but the method he told us to use didn't seem to work.
What we tried was something along the lines of
window.Controller.bind("change:idBoardCurrent", OMGITWORKED);
where idBoardCurrent is a member of window.Controller and OMGITWORKED is the function we'd like to be called when window.Controller.idBoardCurrent is changed.
I'm not very familiar with JavaScript or data binding, so I have no idea if this is right or wrong, or what is correct or incorrect about it. If someone could point out what to change in this snippet, or if they could suggest another way to go about this, I would be very appreciative.
You can use Object.defineProperty to define a setter and getter for the Objects property
Object.defineProperty(window.Controller,"idBoardCurrent",{
get : function() { return this.val; },
set : function(value) {this.val = value;OMGITWORKED(value); }
});
function OMGITWORKED(param) {
console.log("idBoardCurrent has been Changed to " + param);
}
window.Controller.idBoardCurrent = "Test";
window.Controller.idBoardCurrent = "Test2";
console.log(window.Controller.idBoardCurrent)
Edit: changed the code according to the contexts object
JSBin
As this is specifically Firefox, you can use the mutation events it provides. But note the caveats on them from that page:
The W3C specification for them was never widely implemented and is now deprecated
Using DOM mutation events "significantly degrades" the performance of DOM modifications
If you're able to restrict yourselves to Firefox 14 and higher, you can use the new mutation observers stuff instead.
This is, when I am not totally wrong, more a question of javascript.
I found some information about that topic
Listening for variable changes in JavaScript or jQuery
jQuery trigger on variable change
Javascript Track Variable Change
Sorry when I didn't understand the topic.
All the best