Use foundation abide to validate length of a text field? - javascript

I'm using foundation in a rails app and I'm looking for a way to validate the length of text fields in a form: I'd like to display an error when the text field contains too many characters (but not when it's empty).
I tried to use Foundation's abide and create custom named patterns as explained in the docs.
Here are the contents of my application.js file including the custom patterns upon Foundation initialization:
$(function(){
$(document)
.foundation()
.foundation('abide', {
patterns: {
short_field: /^.{,40}$/,
long_field: /^.{,72}$/
}
});
});
And here is my form code in the view:
<form data-abide>
<div class="long-name-field">
<input type="text" pattern="long_field" placeholder="Long Field">
<small class="error">Too long.</small>
</div>
<div class="short-name-field">
<input type="text" pattern="short_field" placeholder="Short Field">
<small class="error">Too long.</small>
</div>
</form>
The problem is that when I load my form page all the fields always display the error message, whether they're empty, filled under their character limit or exceeding their character limit.
Anyone successfully used abide to do something similar (or knows a better way that is not using custom named patterns)?
Cheers.

I finally managed to make it work!
The problem was that /^.{,40}$/ is not a valid regexp syntax, you have to use /^.{0,40}$/ explicitly.
I mistake it with the /.{5,}/ syntax that you can use to impose a only a lower limit.

I could not make the javascript abide work in my Rails 4 app, so I just added the regex directly as an attribute like so:
<%= text_area_tag 'answer', #current_answer,
:placeholder => 'required', :required => '', :pattern => '^(.){0,1000}$' %>
For validating minimum length only I use:
<%= text_area_tag 'answer', #current_answer,
:placeholder => 'required', :required => '', :pattern => '^(.){100,}$' %>

Related

Symfony NucleosAntiSpamBundle

I have a problem with NucleosAntiSpamBundle in my Symfony project.
I installed it as described and I have something like this (just copied example from their github) while loading the web page:
$form = $this->createForm(ContactType::class, null, array(
'antispam_time' => true,
'antispam_time_min' => 10,
'antispam_time_max' => 60,
// Honeypot protection
'antispam_honeypot' => true,
'antispam_honeypot_class' => 'hidden',
'antispam_honeypot_field' => 'email'));
As I can see visualy and also in debugger, the field is added, but is not hidden (it's visible).
So I added also this to CSS:
.hidden{
display:none;
}
But the honeypot field is still visible. In debugger I can see:
<input type="text" id="form_email" name="form[email]" class="hidden form-control">
It seems the "form-control" class overwrites the "hidden" class, because when I remove the "form-control" class and use the hidden, it's properly hidden.
But I am using some bootstrap template and I don't want to change form-control (I am using it everywhere).
Also I didn't find a way how to remove the "form-control" class from the honeypot email field.
How can I fix that?
Many thanks

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.

Rails problem accepts_nested_attributes_for

I have this problem:
My web application has a form where the users can customize their profile.
In each profile can be specified many skills and I want to allow the users to press one button (add new skill) in order to specify as many skills as they want.
So this is the controller code:
accepts_nested_attributes_for :skills, :allow_destroy=>true, :reject_if => lambda {|a| a[:name].blank?}
This is the form (just the part with the nested attribute skill):
<%= f.fields_for :skills do |builder|%>
<div class="field">
<%= builder.label :skill %>
<%= builder.text_field :name%>
<%= builder.hidden_field :_destroy %>
<%= link_to 'remove', '#', :onclick=>'removeField()'%>
</div>
<%end%>
This form work perfectly and shows each skill of the user, it allows editing etc. The problem now, is that I want to add a link to "add new skill" so a javascript function that change the form and add new skill input field, I really have no idea to how to act, mainly because the nested attributes have specific id and name in the form that I don't understand:
<input id="profile_skills_attributes_0_name" name="profile[skills_attributes][0][name]" size="30" type="text" value="Mathematicansszz" />
It also add another hidden input field with the id of the skill (impossible to predict if the skill is not created), make impossible to create new skill from an HTML static pages?
<input id="profile_skills_attributes_0_id" name="profile[skills_attributes][0][id]" type="hidden" value="3" />
Any idea or workaround ? Thank you
I have written a gem that can handle that makes handling nested forms dynamically easier: cocoon.
The gem works with the standard rails formhelpers, but also with formtastic or simple_form.
I would also advise you to checkout formtastic or simple_form, as those are awesome gems to make form-handling easier. But as with HAML, that is a personal choice.
fields_for creates an array of fields. The "0" in the name represents the index in the array. Since you're creating new records you can simply ignore the hidden id field.
So via javascript you just need to do two things:
1. Count the number of existing inputs for the child collection in order to get a new index.
2. Add a new text field using the new index.
This is relatively easy to do with jQuery using a wildcard selector like $('input[name$="][name]"]').length; to retrieve a count (for the new index). If you have another field for array with name fields you may want to use a regex selector instead (via plugin). An easier way might be to just add a class to each of your skill name inputs and use that class as the selector when counting.
To append the new input see:
http://api.jquery.com/append/
If you're not using jquery, then it should be similar in other frameworks with a little googling.

Rails Functional test assert_select javascript respond_to

I am currently trying to write functional tests for a charging form which gets loaded on to the page via AJAX(jQuery). It loads the form from the charge_form action which returns the consult_form.js.erb view.
This all works, but I am having trouble with my testing.
In the functional I can go to the action but I cannot use assert_select to find a an element and verify that the form is in fact there.
Error:
1) Failure:
test_should_create_new_consult(ConsultsControllerTest) [/test/functional/consults_controller_test.rb:8]:
Expected at least 1 element matching "h4", found 0.
<false> is not true.
This is the view.
consult_form.js.erb:
<div id="charging_form">
<h4>Charging form</h4>
<div class="left" id="charge_selection">
<%= select_tag("select_category", options_from_collection_for_select(#categories, :id, :name)) %><br/>
...
consults_controller_test.rb:
require 'test_helper'
class ConsultsControllerTest < ActionController::TestCase
def test_should_create_new_consult
get_with_user :charge_form, :animal_id => animals(:one), :id => consults(:one), :format => 'js'
assert_response :success
assert_select 'h4', "Charging form" #can't find h4
end
end
Is there a problem with using assert_select with types other than html?
Thank you for any help!
So, the problem was that I should put javascript in .js and HTML in .html :P Kinda obvious.
I was putting html into a javascript file. I fixed it by simply renaming charge_form.js.erb to charge_form.html.erb.

Categories