Execution of code which is inside ng-if when it is false - javascript

Imagine I have code like this:
<span>Do you like bananas?</span>
<input type="radio" ng-model="likeBananas" name="likeBananas" value="yes">
<input type="radio" ng-model="likeBananas" name="likeBananas" value="no">
<div ng-if="likeBananas === 'no'">
<label>Tell us why?</label>
<textarea ng-model="whyNot" ng-required="likeBananas === 'no'"></textarea>
</div>
The idea is: if user don't like bananas, <textarea>with explanation is required. If user like bananas, of course it is not required and it's not shown to user. Because mandatory ot this field is dynamic, I used ng-required="likeBananas === 'no', but question is - do I really need it? Maybe simple required can do a job? Because, when ng-if is false, content of div should not be present in HTML. General question is - how Angular execute code inside elements with ng-ifs directive, from top to bottom or from bottom to top? In first case, code inside elements with ng-ifs when it's false should not be executed and, with case above, ng-required is not calculated when div is not present and maybe isn't needed. I hope you would help me with my doubts - thank you in advance.

No, you should use simply ng-required=true into a ng-if directive (in your case), because this directive behavior is removing/adding from the DOM the elements in it when the condition switch.
Thus, if likeBananas !== 'no', the elements
<label>Tell us why?</label>
<textarea ng-model="whyNot" ng-required="likeBananas === 'no'"></textarea>
are not included in the DOM, so the ng-require=true is not compiled.

please have a look here in the plunker:
http://plnkr.co/edit/fqoUbTXICDv0nNQe9aOL?p=preview
by making a form element, you can check it's validity, by doing:
Is the form valid? {{banana.$valid}}

Related

How to combine ng-message messages

I am new to AngularJS but I have searched extensively and could not find a working answer to this question, maybe its just not possible the way I have it in mind.
What I would like is to be able to combine error conditions so that I can use more generic error messages in the ng-messages module. This saves us a lot of time maintaining texts as our application is multi-lingual. In my example it would be great to combine minlength, maxlength, and pattern and have it reference 1 generic message. The only way I have gotten it to work is for a separate ng-message for each type and then reuse the error text which seems redundant to me. Hopefully it's something short I am missing like not understanding when/how to use , or ||.
<form id="myFormId" name="myForm" novalidate>
<input name="sText" ng-model="someText"
type="text"
required
ng-minlength="8" minlength="8"
ng-maxlength="8" maxlength="8"
ng-pattern="/^[a-zA-Z0-9]{8,8}$/" pattern="/^[a-zA-Z0-9]{8,8}$/">
<div ng-messages="myForm.sText.$error" role="alert">
Error message:
<div ng-message="required">Required text missing</div>
<div ng-message="minlength || maxlength || pattern">Not right length or bad pattern - Why does this not work? I have also tried using comma , instead of || </div>
<div ng-message="minlength">Too short - this does work but does not change even if this is removed</div>
</div>
</form>
I have created this simple Plunk to illustrate what I am trying to do:
EDIT 1
I do realize I could use a single regex pattern expression but the above validations is strictly to reproduce the issue and show an example. I have other validations I would like to combine that could not be expressed with a single pattern.
ng-messages will show error message inside ng-messages directive element, but that has limitation that you could only display single error ng-message inside the ng-messages div.
So if you wanted to show multiple ng-message inside ng-messages directive you need to add ng-messages-multiple attribute on ng-messages directive element.
Docs Link
Markup
<div ng-messages="myForm.sText.$error" role="alert" ng-messages-multiple>
Error message:
<div ng-message="required">
Required text missing
</div>
<div ng-message="minlength, maxlength, pattern">
Not right length or bad pattern - Why does this not work? I have also tried using comma , instead of ||(OR)
</div>
<div ng-message="minlength">
Too short - this does work but does not change even if this is removed
</div>
</div>
Working Plunkr
Update
After angular document updation I came to know that ng-messages doesn't support to show multiple ng-message error inside ng-messages, for solving this problem we should have ng-messages-multiple attribute on ng-messages element.
From Docs
By default, ngMessages will only display one error at a time. However, if you wish to display all messages then the ng-messages-multiple attribute flag can be used on the element containing the ngMessages directive to make this happen.
Markup
<div ng-messages="myForm.sText.$error" role="alert" ng-messages-multiple>
Error message:
<div ng-message="required">
Required text missing
</div>
<div ng-message="minlength, maxlength, pattern">
Not right length or bad pattern - Why does this not work? I have also tried using comma , instead of ||(OR)
</div>
<div ng-message="minlength">
Too short - this does work but does not change even if this is removed
</div>
</div>
Working Plunkr
In Angular 1.4 you can specify multiple errors for a ng-message:
<div ng-message="minlength, maxlength">
Your email must be between 5 and 100 characters long
</div>
See documentation
Inorder to make your ng-message more generic you can keep all your error messages at one place and use it when required. You could do this using ng-message-include.
Have a look at : Reusing and Overriding Error Messages
http://www.yearofmoo.com/2014/05/how-to-use-ngmessages-in-angularjs.html#reusing-and-overriding-error-messages.
I think you will like to implement this.

Ruby Watir syntax for setting a text_field with no id and odd parameters

I'm trying to set a text_field and text area on a webpage that doesn't have an id any longer. I'm guessing the site is trying to avoid automation. The input and textarea tags are inside of a form. Here are the input and textarea tags and what is contained.
<input class="uniform-input ng-pristine ng-invalid ng-invalid-required ng-valid-maxlength" type="text" data-invalid-chars="" data-max-length="50" required="" placeholder="Subject" data-float-label="true" data-ng-model="message.Subject"></input>
<textarea class="uniform-input ng-pristine ng-invalid ng-invalid-required ng-valid-maxlength" data-invalid-chars="" data-max-length="4000" required="" placeholder="Enter your message here" data-ng-keypress="view.error = false" data-float-label="true" data-ng-model="message.Body"></textarea>
Also there is a button that I need to click after submitting the text with this button tag:
<button data-ng-if="!paymentInfo" type="button" class="button button-grey ng-scope" data-ng-click="ctrl.sendMessage()" data-ng-disabled="view.waiting" data-ng-class="{ 'button-disabled': view.waiting }">Send Now</button>
How do I click it when it has no name?
Any help as to how to set this with Watir would be very appreciated. If Watir is unable to do it is there a possible JS workaround that I could use? Please let me know if any further information is needed to help.
Using ruby gem watir
require 'watir-webdriver'
$browser = Watir::Browser.new
$browser.goto "yourwebsite.com"
$x = 0
def test
print "#{$x}"
begin
$browser.text_fields[$x].set "#{$x}"
rescue StandardError => e
puts " no text field found, try again.\n\n"
end
$x += 1
end
Keep changing the value of X to see what text fields you are manipulating. I suppose you could make a loop but you might get an error. Keep calling test until you find what you're looking for.
The elements do look like they have some descriptive attributes. The text fields have a data-ng-model that describes the field. As well, the button has a text that is likely unique.
Therefore, I would do:
browser.text_field(:data_ng_model => 'message.Subject').set('subject text')
browser.textarea(:data_ng_model => 'message.Body').set('body text')
browser.button(:text => 'Send Now').click
I think this approach is more expressive in terms of what your code is doing. As well, it can be more robust as it is not susceptible to fields being re-ordered or other fields being added/removed.
I have been identifying those ng-data objects via xpath, mainly when there is not a more specific way to identify them. Justin is right about an approach that is robust; find a way taht does not need to be refactored down the road. Here is what I would have:
browser.text_field(xpath: '//input[#data-ng-model="message.Subject"]').set("Hello")
browser.button(:text => 'Send Now').click
I prefer not using a lot of xpath, except for when it guarantees me a unique way to find an object on a page.

ElasticUI - Triggering search/sort with ng-click

This was taken from a e-mail thread between me and the author. I've moved it from e-mail to SO hoping that it may benefit others. ElasticUI can be found here
My Original Question(s)
I see that search is eui-enabled by querystring.length. We would like to the search and sorting triggered by buttons, rather than the
watch functionality.
It's a bit confusing when the search returns no results. Instead of a no results found message it simply returns the deafualt (all)
results. Is it possible to make the results empty by default, rather
than return all?
Author's Answer
1+2 - this is both possible. In AngularJS, keep in mind what "model"
variable you use and connect to your UI / Directives, something along
the following lines would make sense
<div eui-query="ejs.MatchQuery('textField', querystring)" eui-enabled="querystring.length"> <input type="text" ng-model="querystring_live" />
<input type="button" ng-click="querystring=querystring_live" /> </div>
<div ng-if="!querystring.length"> No query specified </div>
Notice what happens on a click. You could also wrap an ng-if clause
around you're results to only display results when a query has been
specified.
When I include this snippet, the ng-if condition doesn't take (the "No query specified" stays at all times) and after submitting the search, results are blank, even if it's query I'm sure should return results.
Being new to angular, an obvious mistake may go over my head. Is there anything obvious that is missing?
Edit
Found the issue: Forgot to fill in the field with which to run the query against: eui-query="ejs.MatchQuery('post_title', querystring)" ('post_title' being the ES field)
Although it seems like you may have found the answer I think there's still a bug in the "author answer" (me) you posted above. Seems like I fell for the dot-problem in Angular. This should work better:
<div ng-init="qs_model={live:'', after_click:''}">
Debug: {{qs_model | json}}
<h3>Search</h3>
<div eui-query="ejs.MatchQuery('tweet.text', qs_model.after_click)" eui-enabled="qs_model.after_click.length">
<input type="text" ng-model="qs_model.live" />
<input type="button" ng-click="qs_model.after_click=qs_model.live" />
</div>
<div ng-if="!qs_model.after_click.length">No query specified </div>
</div>
It's cleaner to define qs_model in a controller as opposed to ng-init I demoed above.
Also note that even if eui-query is disabled (no querystring specified), ElasticUI will at this moment still do a MatchAll query behind the scenes (you can choose to hide the results using ng-if).

Angularjs ng-model is undefined

In HTML I have this line of code:
<input type="text" class="training-comment" placeholder="Enter comment" ng-model="content" data-ui-keypress="{13:'keypressCallback($event)'}">
And in controller this:
$scope.keypressCallback = function ($event) {
console.log("comment is", $scope.content);
$event.preventDefault();
};
And when I enter some text in input and press enter in console I see that $scope.content is undefined.
Why is this ?
I put together a Plunker example here using the Angular UI and basically copying the code from the question. I then took this example and added an ng-repeat to demonstrate one of the most common issues I have seen: scope issues:
<div ng-repeat="x in collections">
<input type="text" class="training-comment" placeholder="Enter comment"
ng-model="content" data-ui-keypress="{13:'keypressCallback($event)'}" />
<br /><br />
</div>
You can find this updated plunker example here. Basically whenever you use an ng-repeat or any other directive that creates a new scope your model exists in that scope - not the parent or root scope. This means that your code might be working, but it is printing out the value from the wrong scope! For more information on scopes see the angular documentation here.
To use the plunker demo, type into the first input and press the enter key, the model will be updated. But, if you type into either of the other two boxes, though, the model will either not be updated or it will be undefined (if you have never typed into the first box).
Even if this isn't the exact issue, hopefully it will still help. Best of luck!

Speed up :visible:input selector avoiding filter

I have a jQuery selector that is running way too slow on my unfortunately large page:
$("#section").find(":visible:input").filter(":first").focus();
Is there a quicker way to select the first visible input without having to find ALL the visible inputs and then filtering THAT selection for the first? I want something like :visible:input:first but that doesn't seem to work.
[Edit]
Here's the basic idea of what #section looks like:
<div id="section">
<div>
Some text <input type="text">
</div>
<div>
etc. etc. <input type="text">
</div>
</div>
$(":input:visible:first", "#section").focus();
If you first filter for the type of control you avoid checking the :visible on all the #section's elements.
It seems like you need only to catch the first input type="text" visible.
This should be a bit faster.
$("input[type='text']:visible:first", "#section").focus();
How about adding class="default_field" to the default field for each page, then using $('.default_field').focus();?
How easy this is to do depends on your server-side technology of course, but the advantages are that it takes the processing burden off of the client (which is extra important for IE6), and it also gives you the flexibility to choose a default input other than the very first one on pages where it's appropriate.

Categories