I want to auto-validate the input in some <paper-input-container>'s <input is="iron-input"> field, so that it follows a dd.mm.yyyy pattern. Can I do this with the pattern attribute?
I tried pattern="^(\d{2}).\d{2}.(\d{4})$" and pattern="(1-9|0[1-9]|1[0-9]|2[0-9]|3[0-1]).([1-9]|0[1-9]|1[0-2]).(20[1-3][0-9])" together with allowed-pattern="[\d.]", but that doesn't work.
Is the pattern attribute meant to support this use case?
The <paper-input>.pattern is ignored unless you do one of the following:
Enable automatic input validation with <paper-input>.autoValidate
<paper-input auto-validate
pattern="^(\d{2}).\d{2}.(\d{4})$">
</paper-input>
codepen
Manually call <paper-input>.validate() (e.g., on button click)
<paper-input id="input" pattern="..."></paper-input>
<button on-tap="_validateInput">Validate</button>
// script
_validateInput: function() {
this.$.input.validate();
}
codepen
Set <paper-input>.required, and use an <iron-form> wrapper, which automatically calls <paper-input>.validate() on submit
<form id="form" is="iron-form" ...>
<paper-input required
pattern="..."></paper-input>
<button on-tap="_submit">Submit</button>
</form>
// script
_submit: function() {
this.$.form.submit(); // <-- auto validates required form inputs
}
codepen
Related
I'm using the ng-bootstrap typeahead component to search a customer database. When the user selects a customer from the typeahead results list, I navigate to a customer details page. I've got this working, but I want to clear the input field after navigation has taken place. I've tried setting the model to null or an empty string in the selectItem event logic, but this isn't working:
customer-search-typeahead.component.html
<template #resultTemplate let-r="result" let-t="term">
<div>
<div>
{{r.resource.name[0].given}} {{r.resource.name[0].family}}
</div>
<div>
{{r.resource.birthDate | date: 'dd/MM/yyyy'}}
</div>
</div>
</template>
<input type="text" class="form-control" [resultTemplate]="resultTemplate" (selectItem)="onSelect($event)"
[(ngModel)]="model" placeholder="Start typing a customer name..." [ngbTypeahead]="search"/>
customer-search-typeahead.component.ts
#Component({
selector: 'customer-search-typeahead',
template: require('./customer-search-typeahead.component.html'),
styles: [`.form-control { width: 300px; }`]
})
export class CustomerSearchTypeaheadComponent {
model: any;
searching: boolean;
constructor(private customerService: CustomerService, private router: Router) {}
onSelect($event) {
this.router.navigate(['/customers', $event.item.resource.id]);
this.model = null;
};
search = (text$: Observable<string>) =>
//omitted for brevity
}
The typeahead input looks like this after a selection has been made:
Solution
customer-search-typeahead.component.html
<input type="text" class="form-control" #input [ngbTypeahead]="search" (selectItem)="onSelect($event); input.value='' ">
customer-search-typeahead.component.ts
onSelect($event, input) {
$event.preventDefault();
this.router.navigate(['/customers', $event.item.resource.id]);
};
The issue you witnessing arises from the fact that the NgModel directive is updating model binding asynchronously and the actual model is updated after the onSelect method gets executed. So your model update gets overridden by the NgModel functionality.
Fortunately we (ng-bootstrap authors) got all the flex points in place to cover your use-case :-) There are a couple of things that you could do.
Firstly the $event object passed to the onSelect method has the preventDefault() method and you can call it to veto item selection (and as a result writing back to the model and input field update).
$event.preventDefault() will make sure that the model is not updated and the input field is not updated with the selected item. But text entered by a user will still be part of the input so if you want to clear up this as well you can directly update the input's value property.
Here is code demonstrating all those techniques together:
onSelect($event, input) {
$event.preventDefault();
this.selected.push($event.item);
input.value = '';
}
where input argument is a reference to the input DOM element:
<input type="text" class="form-control" #input
[ngbTypeahead]="search" (selectItem)="onSelect($event, input)">
Finally here is a plunker showing all this in practice: http://plnkr.co/edit/kD5AmZyYEhJO0QQISgbM?p=preview
The above one is template ref value solution.
This is for ngModel solution.
Html code:
<input type="text" class="form-control" [resultTemplate]="resultTemplate" (selectItem)="onSelect($event)"
[(ngModel)]="model" placeholder="Start typing a customer name..." [ngbTypeahead]="search"/>
Component code:
onSelect($event) {
$event.preventDefault();
this.model = null;
this.router.navigate(['/customers', $event.item.resource.id]);
};
$event.preventDefault();
for ngModel value change empty
I am trying to construct a meteor template for simplifying creating radio buttons on a form. I would like to be able to pass an array or object as an argument through spacebars to the template. How can I pass an array/object as an argument or is this even possible?
Template:
<template name="radioButton">
<div class="mdl-textfield mdl-js-textfield">{{radioLabel}}</div>
{{#each getRadioOptions}}
<label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="{{radioOptionID}}">
<input type="radio" id="{{radioOptionID}}" class="mdl-radio__button" name="{{radioID}}" value="{{optionID}}">
<span class="mdl-radio__label">{{optionLabel}}</span>
</label>
{{/each}}
</template>
Template helper:
Template.radioButton.helpers({
getRadioOptions: function () {
console.log("getRadioOptions called");
console.log(this);
console.log(this.radioOptions);
return this.radioOptions;
},
radioOptionID: function() {
return this.radioID+"-"+this.optionID;
}
});
Attempted spacebar notation:
{{> radioButton radioID="sampleID" radioLabel="Sample Radio Buttons"
radioOptions=[{optionID:"option1",optionLabel:"Option One"},
{optionID:"option2",optionLabel:"Option Two"}] }}
After running this notation and looking at the browser console, I get back this: (which shows that only null was passed for radioOptions)
getRadioOptions called
Object {radioID: "sampleID", radioLabel: "Sample Radio Buttons", radioOptions: null}
null
You almost got it right, except that you can't give the data as a javascript array but need to use a JSON string, i.e., use:
{{> radioButton radioID="sampleID" radioLabel="Sample Radio Buttons"
radioOptions='[{"optionID":"option1", "optionLabel":"Option One"}, {"optionID":"option2","optionLabel":"Option Two"}]' }}
Note that you need to use quotation marks around the field names, too, because it's JSON and not javascript!
Then, in the helper, parse the string:
getRadioOptions: function () {
console.log("getRadioOptions called");
console.log(this.radioOptions); // string
return JSON.parse(this.radioOptions); // array
},
You cannot pass an object in an #each in spacebars. It has to be an Array. This should appear in your console.
Because Meteor include underscore, what you often pass is _.toArray( myObject ).
I'm using Ember CLI and have noticed odd behaviour. When the user clicks into the input and presses the enter key, the page refreshes.
My page has a basic element like this that is NOT part of any form:
<input type="text" class="form-control" id="per_page" value="50">
I am currently serving the page via:
ember cli
So node is hosting and has the fancy live reload thing going on so that when I update a page that is part of the underlying app.
So what is causing a page reload the enter key pressed inside an input? Could it be node or live reload? Are inputs just supposed to refresh a page when a user presses the enter key and I missed that in my HTML for dummies book?
**Better still, how can I intercept and instead call a function via:
{{action** "myFunction"}}
That happens because when you hit Enter, form gets submitted which results in page reload. what you need to do is set onsubmit="return false" on the form so nothing happens during submit. you can bind input to execute some action by adding action attribute action="doSomething"
<form onsubmit="return false">
{{input type="text" action="createComment" value=topic id="inputTopic"}}
</form>
Edit: In Ember 3+ you now use the {{on}} modifier to setup events on elements.
<form {{on 'submit' this.submitForm}}>
<!-- the rest of your form here -->
<button type='submit'>Submit</button>
</form>
And the action defined like so
#action
submitForm(event) {
event.preventDefault();
// Your code
}
Historically Ember has handled this use case with the following code:
<form {{action 'submitForm' on='submit'}}>
<!-- the rest of your form here -->
<button type='submit'>Submit</button>
</form>
This prevents the form from refreshing the page.
There is another method that gives you more control, by giving you the event so you can manage that yourself:
<form onsubmit={{action 'submitForm'}}>
<!-- the rest of your form here -->
<button type='submit'>Submit</button>
</form>
In this case, you will get an event and will have to call event.preventDefault() to stop the page refresh.
actions: {
submitForm(event) {
event.preventDefault();
}
}
This is a running example of the two: https://ember-twiddle.com/827820958e054f7af57b7677630729fc?openFiles=controllers.application.js%2C
I had the same problem - what worked for me, was to overwrite the keyPress Event in the input component like this:
keyPress: function (e) {
var keyCodeEnter = 13;
if (e.keyCode === keyCodeEnter) {
return false;
}
}
Hope it will help someone in the future! :)
Given this chunk of HTML:
<div id="email_field" class="control-group">
<label class="control-label" for="account.email">Email</label>
<div id="email_input" class="controls">
<input id="account.email" name="account.email" type="text" placeholder="jpublic#example.com">
<span class="help-block">We just need a valid email address.</span>
</div>
</div>
How do I turn this into a re-usable partial for whatever attribute I want? IE: email, password, password confirmation, etc.
I would assume some sort of view hierarchy but I'm not quite sure.
EDIT: After further exploration I've knocked out {{view}} and {{render}} and figured out exactly what I need:
I want to:
1. Use a specific view (InputView)
2. Use a specific controller (Preferably similarly named: InputController) ({{view}} doesn't do this I think)
3. Be able to use this multiple times ({{render}} can't do this)
4. Be able to pass in values ({{render}} can't do this)
Example:
<!-- templates/application.hbs -->
{{foo "input" name="Email" id="account.email" placeholder="jpublic#email.com"}}
// controllers/input.js
Application.InputController = Ember.ObjectController.extend({
type: "text"
});
// views/input.js
Application.InputView = Ember.View.extend({
templateName: "form/input"
});
<!-- templates/form/input.hbs -->
<input {{bindAttr id="id" name="name" type="type" placeholder="placeholder"}}>
I would create a view that takes all the parameters that are variable. Such as:
{{view App.FormEntity
name="email"
placeholder="My placeholder..."
help="We just need a valid email address."
valueBinding="value"
}}
From there you could extract the label, the various class names, and then use Ember.TextField to bind the value to.
Once you have all of those arguments passed into the view, it should be nice and easy to create the markup using a mixture of bindAttrs, a couple of computed properties, and Ember helpers (such as the Ember.TextField).
I am new to Emberjs and looking for pretty much the same thing, but couldn't you also simply use http://emberjs.com/guides/templates/writing-helpers/ for that?
I will try it myself, so can give more updates if that works out.
Update:
Ok, I got it to work. I created a new Helpers folder with FormgeneratorHelper.js and the following code:
Ember.Handlebars.registerBoundHelper('control-group', function (options) {
var name = options.hash.test.capitalize();
console.log(name);
return new Handlebars.SafeString('<div class="control-group"> \
<label class="control-label" for="input' + name + '">' + name + '</label> \
<div class="controls"> \
<input type="text" id="input' + name + '" placeholder="' + name + '" /> \
</div> \
</div>');
});
An then, no matter in which template you can do:
{{control-group test="email"}}
I really like the idea of using helpers, but if you are using plain Javascript (as opposed to CoffeScript) and have more than one line of code, then it gets a bit ugly unfortunately. But will probably still use that method.
How do I turn this into a re-usable partial for whatever attribute I want? IE: email, password, password confirmation, etc.
What you want is the experimental {{control}} helper. The control helper is currently under development and is considered experimental. To enable it, set ENV.EXPERIMENTAL_CONTROL_HELPER = true before requiring Ember.
I want to:
1. Use a specific view (InputView)
2. Use a specific controller (Preferably similarly named: InputController) ({{view}} doesn't do this I think)
Out-of-box the control helper expects to be passed a template name. That template name is used to lookup a matching view and controller. So for example:
App.InputView = Ember.View.extend()
App.InputController = Ember.Controller.extend()
{{control input}}
See:
A control renders a template with a new instance of the named controller and view
A control's controller and view are lookuped up via template name
Be able to use this multiple times ({{render}} can't do this)
A control can be used multiple times
Be able to pass in values ({{render}} can't do this)
Like the {{view}} helper, {{control}} will accept arbitrary name/value pairs. So as in your example, one could manually pass options to the control helper. Like the {{view}} helper these options become properties on the view instance:
<!-- templates/form/input.hbs -->
<label class="control-label" {{bindAttr for="view.inputId"}}>
{{view.label}}
</label>
<div class="controls">
<input {{bindAttr id="view.inputId" name="view.name" type="type" placeholder="view.placeholder"}}>
<span class="help-block">{{view.help}}</span>
</div>
// controllers/form_input.js
App.FormInputController = Ember.ObjectController.extend({
type: "text"
});
// views/form_input.js
App.FormInputView = Ember.View.extend({
classNames: ["control-group"]
});
<!-- templates/application.hbs -->
{{control "form/input"
inputId="account.email"
name="email"
label="Email"
placeholder="jpublic#email.com"
help="We just need a valid email address."
}}
See this jsbin for working example
Also keep in mind that A control can specify a model to use in its template - with this in place we can bind properties to model data. Also if a controller's model changes, its child controllers are destroyed so the control will reset as expected if the model is swapped out.
I have a contact form where users will enter their details like name, address, phone and so on. Now I have a checkbox (remember me) on the form.. whenever the user checks this, the information should be saved in a cookie and retrieved when the same user visits later. This is how i started..
<tr><td><input id="mycheck" name="mycheck" data-dojo-type="dijit.form.CheckBox" value="" checked="false" onChange="setCookie" > <label for="mycheck" >Remember me </strong></label></td></tr>
setCookie: function () {
cookie("UserInfo", "cookieValue", { expire: 5 });
},
How do i get the cookie values (this should be whole forms data..do i need to use something like byId)...confused..any ideas??
Thanks
see http://dojotoolkit.org/reference-guide/1.7/dojo/cookie.html
if using > 1.7 you should pull in the required module and use it by reference (as it looks like youre doing):
NOTE is not {expire:X} but {expires :x}
<script>
require(["dojo/cookie"], function(cookie){
/* set */
cookie(cookieName, cookieValue, cookieProps);
/* get */
cookie(cookieName);
});
</script>
You can use dojo/dom-form module to pull values and save them for a neet one-liner
<form id="myform">
<input type="text" name="field1" value="value1">
<input type="text" name="field2" value="value2">
<input type="button" name="someButton" value="someValue">
</form>
<script>
require(["dojo/dom-form", "dojo/cookie"], function(domForm, dCookie){
dCookie(
"formdata",
domForm.toJson("myId"),
{expires: 5}
);
// The cookie will read: '{"field1":"value1", "field2":"value2"}'
// Note the button was skipped.
// Buttons only gets sent when used as submitbutton + onclick
});
</script>
Serialize the value to JSON then undo it when you retrieve like so:
//Setting the cookie to hold an array of values.
value = {my:"1",cookie:"2"};
dojo.cookie("myCookie", dojo.toJson(value), {expires: 30});
//Retrieving the cookie.
newValues = dojo.fromJson(dojo.cookie("myCookie"));