I have such an autocomplete component I created. I allows the user to type in text, and upon typing the options list is filtered and he can click on one of the options.
<mat-form-field appearance="outline">
<mat-label>{{ title | translate }}</mat-label>
<input type="text" matInput [matAutocomplete]="autocomplete" (change)="onInputChange($event)" />
<mat-autocomplete #autocomplete="matAutocomplete">
<mat-option *ngFor="let item of filteredItems " [value]="item.item" (onSelectionChange)="onOptionSelectionChange($event)">
{{ item.item }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
I need to catch the changes the user does, both by typing and by selecting.
What happens is that when user start to type, and clicks on one of the items, the onInputChange is triggered by the input's onInputChange, but not the onOptionSelectionChange. He needs to click a second time on order to it executed.
If user clicks on a value from the list without typing in text before in the input, the onOptionSelectionChange does work on first click.
How can I make that upon typing and then selecting an iten, both onInputChange and onOptionSelectionChange will be triggered?
Thanks!
Related
I am using the double-binding of the clrDate, which allows me to load a Javascript Date object. However, I need to trigger an event every time the user changes the date, either types in a new one or uses the calendar.
I've tried (click), (change), (ngModelChange), (blur) - but for some reason none of them seem to trigger.
<label for="modelDate" class="clr-control-label" >Model Date:</label>
<input clrDate type="date" [(clrDate)]="selectedModelDate" (ngModelChange)="loadModel(false)" >
How should I capture the change within the Date Picker?
You can do it in two ways.
2-way Binding
In this stackblitz, notice that before the date picker is interaced with, if you click the button then the value of date1 is undefined. After you select a date and click the button it has the value set in the date picker. This is typical 2-way binding in Angular.
<section>
<button class="btn btn-primary" (click)="logDate1()">
Log Date Value for 2-way binding
</button>
<label for="date1" class="clr-control-label" > Date1:</label>
<input type="date" [(clrDate)]="date1" />
</section>
De-sugarized Syntax
This might be what you are after. It's almost the same as the above example but we seperate or de-sugarize the 2-way binding so that it gets set with [clrDate]=date2. Notice that it fires an event clrDateChange that can be tied into with the logChnage($event). That will get fired whenever the internal value of the date picker changes (e.g user selects a date) and you can do whatever you want with it's value in the logChange function. This is 2-way binding de-sugarized.
<section>
<h4>De-sugarized syntax</h4>
<label for="date2" class="clr-control-label" > Date1:</label>
<input type="date" [clrDate]="date2" (clrDateChange)="logChange($event)"/>
</section>
Sounds so simple but I've tried quite a few things and none work.
I'm using Angular 4 and my form is template-driven:
<form #form="ngForm" novalidate>
<label for="insz">{{ 'SEARCH_PAGE.searchInszNumber' | translate }}</label>
<input type="text" name="insz" [placeholder]="'SEARCH_PAGE.searchInszNumber' | translate" #input required>
<button (click)="onSearch(input.value)" ><span>{{'SEARCH_PAGE.search' | translate }}</span></button>
</form>
I want to disable the button when the (one and only) input field is empty.
You are missing ngModel in your input, for your input field to actually be a form control:
<input type="text" name="insz" ngModel
[placeholder]="'SEARCH_PAGE.searchInszNumber' | translate" #input required>
and then you need to disable the button of course if form is not valid:
<button [disabled]="!form.valid" (click)="onSearch(input.value)" >Submit</button>
You could take a look at reactive forms. I had no knowledge of them until a week ago, but they're so powerful !
This means all you need to do is add a Validator (Validators.required in your case), and add a disabled condition to your button. And that's it, you're set.
I have a form with aria-describedby attributes on the input alements, followed by a span tag with a description/example of the desired input. It also has class to only display for screenreaders (sighted people can make use of the placeholder information instead).
The issue here is that, according to Fangs at least, the screenreader reads the label, then prompts for input, then reads the aria-describedby text.
Can I move the text above the input in the code, e.g.
<label for="givenName">Given name</label>
<span id="givenNameHelp" class="help-block sr-only">e.g. Liam</span>
<input class="form-control" type="text" id="givenName" placeholder="Liam" aria-describedby="givenNameHelp">
if you are already adding an HTML label to the input, you don't need to use ARIA attributes at all. You can safely remove the aria-describedby, and nest the span content. Example:
<label for="givenName">Given name
<span id="givenNameHelp" class="help-block sr-only">e.g. Liam</span>
</label>
<input class="form-control" type="text" id="givenName" placeholder="Liam">
Hope it helps!
As a general rule..First try to make accessible content with standard HTML. Then, use ARIA to describe website sections, widgets and interactive behavior (like menues, tabs, pop ups, messages, dropdowns, calendars, etc), and also to describe what you could not do with HTML.
I have a form with aria-describedby attributes on the input alements, followed by a span tag with a description/example of the desired input. It also has class to only display for screenreaders (sighted people can make use of the placeholder information instead).
The issue here is that, according to Fangs at least, the screenreader reads the label, then prompts for input, then reads the aria-describedby text.
Can I move the text above the input in the code, e.g.
<label for="givenName">Given name</label>
<span id="givenNameHelp" class="help-block sr-only">e.g. Liam</span>
<input class="form-control" type="text" id="givenName" placeholder="Liam" aria-describedby="givenNameHelp">
Yes, this is perfectly legitimate and will work with all screen readers
I'm building a form that generates an invitation when submitted. The invitation has several fields, one of which is an email address input with an 'add' button, which when clicked should add that address to a list of email addresses that should receive the invite.
This can be done with a single form, however if the user hits the enter key while typing an email then it triggers submit on the whole form. I'd like to have the enter key result - when the email input field is focused - have the same effect as clicking the 'add' button. I expected that the proper way to solve this would be to nest an email entry form within the invitation form, something like this:
<ng-form ng-submit="sendInvite()">
<input type="text" placeholder="Title" ng-model="invitation.title"/>
<ng-form ng-submit="addInvitee()">
<input type="email" placeholder="Title" ng-model="inviteeEmail"/>
<button class="btn" type="submit">add</button>
</ng-form>
<button class="btn" type="submit">Send</button>
</ng-form>
With the following javascript in the controller:
$scope.addInvitee = function() {
$scope.invitation.emails.push($scope.inviteeEmail);
$scope.inviteeEmail = '';
}
$scope.sendInvite = function() {
//code to send out the invitation
}
My problem is that having nested the forms (and in doing so converted from <form> to <ng-form>, submitting either one no longer works.
Plunker here
I've similar requirement - wizard driven multi-step form. When user clicks 'Next' button, I've to validate the current step form.
We can trigger validation by firing '$validate' event on the scope bound to the form.
isFormValid = function($scope, ngForm) {
$scope.$broadcast('$validate');
if(! ngForm.$invalid) {
return true;
}
}
When ever I want to check if the form values are correct, I'll call isFormValid with the scope & form instance.
Working code: Plunker link
It is also useful to have few additional logic in isFormValid (included in the above Plunker) which makes the form & form fields $dirty as we would be showing/hiding validation messages based on their $dirty state.
You can use one of the following two ways to specify what javascript method should be called when a form is submitted:
* ngSubmit directive on the form element
* ngClick directive on the first button or input field of type submit (input[type=submit])
-- form docs
<ng-form>
<input type="text" placeholder="Title" ng-model="invitation.title"><br>
<ng-form>
<input type="email" placeholder="Title" ng-model="inviteeEmail">
<button class="btn" ng-click="addInvitee()">add</button><br>
</ng-form>
<ul class="unstyled">
<li ng-repeat="invitee in invitation.invitees">
<span>{{invitee.email}}</span>
</li>
</ul>
<button class="btn" ng-click="sendInvite()">Send</button>
</ng-form>
Plunker
When the form is submitted, you can find all nested forms using some thing like below
forms = []
forms.push(form)
nestedForms = _.filter(_.values(form), (input) -> (input instanceof form.constructor) and (input not in forms))
Here, form is the outer form controller which was submitted. You can hook this code on ur onsubmit, and find all nested forms and do whatever you have to.
Note: This is coffeescript