I am expecting that the previous value on firstname is removed and then I can write the new value. But it is not removing the name.
Clear() function is not helping here.
var firstname= element(By.model('subject.firstName'));
firstname.clear().then(function() {
firstname.sendKeys('bob');
})
HTML:
<input type="text" ng-model="subject.firstName"
placeholder="First Name" name="firstName" validator="required"
valid-method="submit" message-id="requireFirstName"
ng-maxlength="50" class="ng-pristine ng-pending ng-empty
ng-valid-maxlength ng-touched">
Protractor version: 4.0.11
I generally add click() event before performing clear() or sendKeys(), just to make sure focus is on element. For example:
element(by.model('anyvalue')).click().clear().sendKeys(value);
Make sure you have an element with model anyvalue on your website.
Change
element(By.model...
to
element(by.model...
I believe that you don't have to use then() on clear, even though it returns a promise. So you can check if this will work:
firstname.clear();
firstname.sendKeys('bob');
This is my view file containing the form that has to filled in by the user:
#helper.form(call) {
#helper.input(resumeForm("surname"), '_label -> "Surname") { (id, name, value, args) =>
<input name="#name" type="text" value="#value" placeholder="Enter your surname">
}
}
This is my custom field constructor:
#(elements: helper.FieldElements)
#if(!elements.args.isDefinedAt('showLabel) || elements.args('showLabel) == true) {
<div class="input-with-label text-left">
<span>#elements.label</span>
#elements.input
</div>
} else {
#elements.input
}
Now I have a dilemma. When the entered value doesn't clear validation, I need to add the class field-error to the input and I need to add data-toggle, data-placement and title. However, I don't know of any way to check if there are errors for the specific field. What is the best way to implement this? I already looked at using inputText or something but that is basically the same as the base input thus also does not have access to any errors. I'm also unable to alter the HTML of the elements.input inside the field constructor.
Have a look at play documentation: Writing your own field constructor.
You can check on errors with #if(elements.hasErrors) within the template of your custom field constructor.
<div class="input-with-label text-left #if(elements.hasErrors){field-error}">
...
Edit:
You can pass the error state of your field via the args parameter to your input. From the play docs:
Note: All extra parameters will be added to the generated HTML, except for ones whose name starts with the _ character. Arguments starting with an underscore are reserved for field constructor argument (which we will see later).
You need to cast to the matching type though.
#input(resumeForm("surname"), '_label -> "Surname", 'hasErrors -> resumeForm("surname").hasErrors) { (id, name, value, args) =>
<input name="#name" type="text" value="#value" placeholder="Enter your surname"
class="#if(args.get('hasErrors).map(_ match { case x:Boolean => x}).get){field-error}">
}
I'am trying to have auto complete and onBlur functionality attached to the same input field using Liftweb framework.
I have them working independently.
What I'am trying to do is have an auto complete input field and on selecting the value from the suggestion, some business logic is to be performed and another input field needs to be updated.
But only the auto complete feature is working.
This is the form
<form class="lift:CapitalOnBlur">
Country : <input id="countryNameOnBlur" type="text" name="countryNameOnBlur"/><br />
Capital: <input id="capitalNameOnBlur" type="text" name="capital"/>
</form>
This is the snippet
object CapitalOnBlur {
val capitals: Map[String, String] = Map(
"india" -> "New Delhi",
"uganda" -> "Kampala",
"japan" -> "Tokyo")
def render = {
def callback(countryName: String): JsCmd = {
val capital = capitals.getOrElse(countryName.toLowerCase, "Not Found")
SetValById("capitalNameOnBlur", capital)
}
val default = ""
def suggest(value: String, limit: Int) = capitals.filter(_._1.startsWith(value.toLowerCase)).keys.toSeq
def submit(value: String) = Unit
"#countryNameOnBlur" #> AutoComplete(default, suggest, submit) &
"#countryNameOnBlur [onBlur]" #> SHtml.onEvent(callback)
}
}
This is what I actually want to do. I tried this and only onBlur event is triggered.
According to my needs, When I start typing the country name in the first input field, it should show me the suggestions and on selecting the suggestion i.e.; onBlur from that input field, the corresponding capital should be rendered in the next input field.
And also is there a way to trigger an action on selecting a suggestion using the inbuilt Auto complete feature of lift.
I am adding this as a separate answer since the edit is essentially a separate question. The AutoComplete widget from Lift does not modify an existing element on the page, but rather replaces it with the following NodeSeq, as per the source.
<span>
<head>
<link rel="stylesheet" href={"/" + LiftRules.resourceServerPath +"/autocomplete/jquery.autocomplete.css"} type="text/css" />
<script type="text/javascript" src={"/" + LiftRules.resourceServerPath +"/autocomplete/jquery.autocomplete.js"} />
{Script(onLoad)}
</head>
<input type="text" id={id} value={default.openOr("")} />
<input type="hidden" name={hidden} id={hidden} value={defaultNonce.openOr("")} />
</span>
Since that has now replaced the original HTML, the second line where you add an onBlur handler is not applied to anything useful. However, the AutoComplete constructor does take an optional parameter for attributes and you can probably use that to add an onBlur attribute to the input tag.
You can try something like this:
"#countryNameOnBlur" #> AutoComplete(default, suggest, submit,
("onBlur", SHtml.onEvent(callback).cmd.toJsCmd))
The above should pass in a tuple which specifies the attribute name, and the string representation of the Javascript you want executed. This should accomplish what you are looking for as long as the AutoComplete library doesn't also rely on the onBlur event. That case is doable too, but a bit more work.
One other thing to note is that onBlur is fired when the input loses focus, ie: the user moves the cursor to another field. If you want it to fire any time the text changes, regardless of cursor position, you may prefer the onChange event.
If you are looking to bind to different events on the same element, so that you end up with something like: <input onblur="getCapitalName" onchange="autoComplete">, you can try using SHtml.onEvent. Something like this in your snippet should do the trick:
object CapitalOnBlur {
def render =
"* [onblur]" #> SHtml.onEvent(e => CapitalOnBlur.getCapitalName(e)) &
"* [onchange]" #> SHtml.onEvent(e => CapitalOnBlur.autoComplete(e)) &
...
}
And then call the snippet from your input, like this:
<form>
Country : <input id="countryNameOnBlur" data-lift="CapitalOnBlur" type="text" name="countryNameOnBlur"/><br />
</form>
I am not sure what any of the arguments your code takes, so the above is mostly illustrative - but will hopefully get you on your way.
I have an array of Person objects
var persons = [
{Name:'John',Eligible:true},
{Name:'Mark',Eligible:true},
{Name:'Sam',Eligible:false},
{Name:'Edward',Eligible:false},
{Name:'Michael',Eligible:true}
];
and i am using select with ng-options like this:
<select ng-model="Blah" ng-options="person.Name for person in persons"></select>
I want to show the record with Eligible:false in red color.
So the problem is how do i use the ng-class in select inorder to achieve this? Since we are not using any option tag it wont work if i simply add ng-class in the select element itself.
You could create a directive that processed the options after the ngOptions directive is processed that updated them with the appropriate classes.
Update: The old code had a few bugs, and I've learned a bit since I answered this question. Here is a Plunk that was redone in 1.2.2 (but should work in 1.0.X as well)
Here is updated (Nov 30 '13 at 3:17) the Code:
app.directive('optionsClass', function ($parse) {
return {
require: 'select',
link: function(scope, elem, attrs, ngSelect) {
// get the source for the items array that populates the select.
var optionsSourceStr = attrs.ngOptions.split(' ').pop(),
// use $parse to get a function from the options-class attribute
// that you can use to evaluate later.
getOptionsClass = $parse(attrs.optionsClass);
scope.$watch(optionsSourceStr, function(items) {
// when the options source changes loop through its items.
angular.forEach(items, function(item, index) {
// evaluate against the item to get a mapping object for
// for your classes.
var classes = getOptionsClass(item),
// also get the option you're going to need. This can be found
// by looking for the option with the appropriate index in the
// value attribute.
option = elem.find('option[value=' + index + ']');
// now loop through the key/value pairs in the mapping object
// and apply the classes that evaluated to be truthy.
angular.forEach(classes, function(add, className) {
if(add) {
angular.element(option).addClass(className);
}
});
});
});
}
};
});
Here's how you'd use it in your markup:
<select ng-model="foo" ng-options="x.name for x in items"
options-class="{ 'is-eligible' : eligible, 'not-eligible': !eligible }">
</select>
It works like ng-class does, with the exception that it's on a per-item-in-the-collection basis.
In this scenario you can only apply ng-class only if you use ng-repeat with option tags:
<select ng-model="Blah">
<option ng-repeat="person in persons" ng-class="{red: person.Eligible}">
{{person.Name}}
</option>
</select>
This will give custom class to your 'Eligible' persons, but CSS won't work consistently across bowsers.
Plunker.
I wanted to comment on the accepted answer, but because I don't have enough reputation points, I must add an answer.
I know that this is an old question, but comments where recently added to the accepted answer.
For angularjs 1.4.x the proposed directive must be adapted to get it working again.
Because of the breaking change in ngOptions, the value of the option isn't anymore the index, so the line
option = elem.find('option[value=' + index + ']');
won't work anymore.
If you change the code in the plunker to
<select ng-model="foo" ng-options="x.id as x.name for x in items"
options-class="{ 'is-eligible' : eligible, 'not-eligible': !eligible }">
</select>
As result the value of the option tag will now be
value="number:x" (x is the id of the item object)
Change the directive to
option = elem.find('option[value=\'number:' + item.id + '\']');
to get it working again.
Of course this isn't a generic solution, because what if you have not an id in your object?
Then you will find value="object:y" in your option tag where y is a number generated by angularjs, but with this y you can't map to your items.
Hopes this helps some people to get their code again working after the update of angularjs to 1.4.x
I tried also to use the track by in ng-options, but didn't get it to work.
Maybe people with more experience in angularjs then me (= my first project in angularjs)?
The directive is one way, but I used a custom filter.
If you know how to select your element, you should be fine here. The challenge was to find the current option element inside the select. I could have used the "contains" selector but the text in the options may not be unique for items. To find the option by value, I injected the scope and the item itself.
<select ng-model="foo" ng-options="item.name|addClass:{eligible:item.eligible,className:'eligible',scope:this,item:item} for item in items"></select>
and in the js:
var app = angular.module('test', []);
app.filter('addClass', function() {
return function(text, opt) {
var i;
$.each(opt.scope.items,function(index,item) {
if (item.id === opt.item.id) {
i = index;
return false;
}
});
var elem = angular.element("select > option[value='" + i + "']");
var classTail = opt.className;
if (opt.eligible) {
elem.addClass('is-' + classTail);
elem.removeClass('not-' + classTail);
} else {
elem.addClass('not-' + classTail);
elem.removeClass('is-' + classTail);
}
return text;
}
})
app.controller('MainCtrl', function($scope) {
$scope.items = [
{ name: 'foo',id: 'x1',eligible: true},
{ name: 'bar',id: 'x2',eligible: false},
{ name: 'test',id: 'x3',eligible: true}
];
});
Here you can see it work.
The accepted answer did not work for me, so I found an alternative without a custom directive using track by :
<select ng-model="foo" ng-options="x.name for x in items track by x.eligible"></select>
Each option now gets the value x.eligible. In CSS you can style options with value = true (I think true has to be a string). CSS:
option[value="true"]{
color: red;
}
In case you not only want to show them in red color but prevent the user from selecting the options, you can use disable when:
<select
ng-model="Blah"
ng-options="person.Name disable when !person.Eligible for person in persons">
</select>
You can then use CSS to set the color of disabled options.
I can't write this as a comment, due to reputation, but I have updated the plunker for the accepted answer to work with Angular 1.4.8. Thanks to Ben Lesh for the original answer, it helped me a lot. The difference seems to be that newer Angular generates options like this:
<option class="is-eligible" label="foo" value="object:1">foo</option>
so the code
option = elem.find('option[value=' + index + ']');
wouldn't be able to find the option. My change parses ngOptions and determines what field of item was used for the label, and finds the option based on that instead of value. See:
http://plnkr.co/edit/MMZfuNZyouaNGulfJn41
I know I am a bit late to the party, but for people who want to solve this with pure CSS, without using a directive you can make a css class like this:
select.blueSelect option[value="false"]{
color:#01aac7;
}
This css rule says : Find all elements with value = false with tag name 'option' inside every 'select' that has a class "blueSelect" and make the text color #01aac7; (a shade of blue)
In your case your HTML will look like this:
<select class="form-control blueSelect" name="persons" id="persons1"
ng-options="person as person.name for person in $ctrl.persons track by person.Eligible"
ng-model="$ctrl.selectedPerson" required>
<option disabled selected value="">Default value</option>
</select>
The track by inside the ng-options is what will hold what to track the options by, or the "value" field of each option. Notice that depending on your project needs , you might have to do some tweaking to make this work as per your requirements.
But that's not going to work right when there's multiple options with the same value for the Eligible field. So to make this work, we create a compound expression to track by, that way we can have unique values to track by in each option. In this case we combine both fields Name and Eligible
So now our html will look like this
<select class="form-control blueSelect" name="persons" id="persons2"
ng-options="person as person.name for person in $ctrl.persons track by (person.name + person.Eligible)"
ng-model="$ctrl.selectedPerson" required>
<option disabled selected value="">Default value</option>
</select>
and our css :
select.blueSelect option[value*="False"]{
color:#01aac7;
}
Notice the * next to value, this is a regular expression which means to find the word "False" somewhere in the value field of the option element.
Quick Edit
You can also choose to disable the options with Eligible = False using the "disable when" in the ng-options expression , for example:
label disable when disable for value in array track by trackexpr
I'll leave how to use that in your case for you to find out ;-)
This works for simple css modifications, for more complex stuff you might need a directive or other methods. Tested in chrome.
I hope this helps someone out there. :-)
I've found another workaround that was easier than adding a directive or filter, which is to add a handler for the onfocus event that applies the style.
angular.element('select.styled').focus( function() {
angular.element(this).find('option').addClass('myStyle');
});
Greetings. I have some inputs dynamically added to form.
<input name="input_names[]" />
When form was posted, I can get these names like this:
var names = Request.Form["input_names[]"];
And I've got CSV string. It's not a problem and I can split it by comma. Problem happens when I write down text which includes comma. Then I cannot split this string correctly. Split method will divide single string into two or more and that's a problem.
How can I avoid this problem?
One way would be to call them:
<input type="text" name="inputNames" />
<input type="text" name="inputNames" />
...
And in your controller action:
[HttpPost]
public ActionResult Index(string[] inputNames)
{
return View();
}
This way you don't have to worry about splitting. You controller action will already receive an array.