Angular Material datepicker manual open - javascript

In the datepicker documentation there is an example of the popup calendar being controlled programatically by using the open() and close() methods like so:
<mat-form-field class="example-full-width">
<input matInput [matDatepicker]="picker" placeholder="Choose a date">
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
<button mat-raised-button (click)="picker.open()">Open</button>
One can also set the opened property to true/false like so:
<button mat-raised-button (click)="picker.opened = true">Open</button>
I wonder if there is anyway to use this to get the calendar popup to stay permanently opened for the purpose of letting the user click around on different dates, and having those selection reflected in the input?

I guess you can try this :
<mat-form-field class="example-full-width">
<input matInput (dateChange)="reOpenCalendar()" [matDatepicker]="picker" placeholder="Choose a date">
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
<button mat-raised-button (click)="picker.open()">Open</button>
in your component ts/js file you need to declare a new method :
export class YourComponent{
#ViewChild('picker') picker;
//....
reOpenCalendar(){
let self = this;
setTimeout(
()=>{
self.picker.open();
},
50
);
}
}
This will introduce a flash effect as the date picker disappears and quickly reappears.
The other solution would be fork angular material datepicker component in your local project and introduce an Input property to disable the closing when a date is selected

The built-in datepicker control of Material library comes with an internal Calendar component. You can use the following to have a calendar that is always open (without the input box but still works with date/month/year selection)
Read more about the calendar here:
https://onthecode.co.uk/angular-material-calendar-component/

Related

mat-datepicker opens in different place

I have my mat-datepicker in 2 places on the page. And when I'm clicking on the one place, it opens in an oposite place. How can I fix that? I have 2 different components with mat-datepicker, but it opens different.
Maybe the problem is that I imitate click in one component? But why it opens different one?
Here's the code
Opens here: (child.components.html)
<mat-form-field appearance="fill">
<input matInput [matDatepicker]="picker">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker ngDefaultControl></mat-datepicker>
</mat-form-field>
Clicks here: (parent.component.html)
<mat-form-field appearance="fill">
<mat-label>Choose a date</mat-label>
<input [min]="minDate" (dateInput)="onDate($event)" matInput [matDatepicker]="picker" (keydown)="false">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker ngDefaultControl></mat-datepicker>
</mat-form-field>
Onchange event opens Calendar like this:
public onTabChange(event: MatButtonToggleChange): void {
setTimeout(() => {
const element: HTMLElement = document.getElementsByClassName('mat-icon-button')[0] as HTMLElement;
element.click();
}, 200);
}
try give differents "template reference variable" (replace one #picker by, e.g. #picker2 and replace the picker by picker2.
About imitate click (it's not the problem) I suggest use a ViewChild and directly use open method
import {MatDatepicker} from '#angular/material/datepicker';
#ViewChild('picker2') datepicker:MatDatepicker<any>
public onTabChange(event: MatButtonToggleChange): void {
setTimeout(() => {
this.datepicker.open()
});
}
See that you needn't "wait" the 200 miliseconds. The setTimeout say to angular: "hey you!, repaint the app and after, remember execute the code under the setTimeout" -the same happens if you use change detector and use .markForCheck()-

Angular Material Datepicker toggle icon click event

Is it possible to somehow catch click event on angular material datepicker toggle icon? I want trigger function foo().
My implementation looks like:
<mat-form-field class="example-full-width">
<input matInput [matDatepicker]="picker" placeholder="Date">
<mat-datepicker-toggle matSuffix [for]="picker" (click)="foo()"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
I have already tried put (click)="foo()" to mat-datepicker-toggle and mat-datepicker element but event not triggered.
Use opened and closed event emitter provided by angular date picker component to listen open and close of calander component.
<mat-form-field class="example-full-width">
<input matInput [matDatepicker]="picker" placeholder="Date">
<mat-datepicker-toggle
matSuffix [for]="picker" (click)="foo()"></mat-datepicker-toggle>
<mat-datepicker
#ref
(opened)="toggle(ref)"
(closed)="toggle(ref)"
#picker></mat-datepicker>
</mat-form-field>
Example
Try to (focus)="foo()" instead of (click)="foo()"

mat input with mat-datepicker-toggle problem

I have a form where every required field turns red if the user clicks and blur the field without writing anything on the field, the problem comes with this date picker
<mat-form-field class="contenedorFecha" appearance="outline" color="accent">
<mat-label>Fecha plantación</mat-label>
<input matInput [matDatepicker]="fechaPlantacion" formControlName="fechaPlantacion" readonly (click)="fechaPlantacion.open()">
<div matSuffix style="display:flex; align-items: center">
<mat-datepicker-toggle [for]="fechaPlantacion"></mat-datepicker-toggle>
<button mat-icon-button (click)="deleteDate('fechaPlantacion', $event)" [disableRipple]="true"
*ngIf="fincaForm.get('fechaPlantacion').value !== null">
<mat-icon class="nav-link-icon mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" role="img" aria-hidden="true">close</mat-icon>
</button>
</div>
<mat-datepicker #fechaPlantacion></mat-datepicker>
</mat-form-field>
When I click on the input it opens the matDatePicker, but as it opens the date picker the input blurs, so the input changes to red, any way to prevent this? I've tried with css but the problem is I want the input to be red but only when it should
Yes the problem is because the focus gets out of the input control and goes to the calendar. If you are only using the default button as the trigger to open the date picker, then you won't encounter this issue. But like what you did, sometimes it's better to add that (focus) or (click) trigger. I can only think of one work around.
Start by removing the initial validators from your field. Then put a handler whenever the material date picker was closed such as:
<mat-datepicker #fechaPlantacion (closed)="close()"></mat-datepicker>
and in the close method, you have to set the validators dynamically:
close() {
this.fechaPlantacion.setValidators(Validators.required);
this.fechaPlantacion.updateValueAndValidity(null);
}
This way, the validation will only be added after the selection (or not selecting anything) from the dates in the calendar. I also tried using readonly input and still working fine after testing in my local machine.

How to choose an option in mat select using ANY google chrome extension?

I have a problem with selecting an option in mat-select with the use of google chrome extensions. Extensions can fulfill inputs but mat-selects remains untouched.
I've tried to use extensions like: Autofill, Form-O-Filler. By default extensions can't reach mat-selects. To obtain my goal I used javascript code to select option/value but it didnt work.
My summarized mat-select looks like this:
<mat-form-field appearance="outline" class="name">
<mat-select formControlName="name"
[mctPristine]="group?.name"
name="name"
id="name">
<mat-option *ngFor="let name of names" [value]="name">
name
</mat-option>
</mat-select>
</mat-form-field>
I have used code below to choose value:
document.getElementById('name').value='Patryk';
and this:
document.getElementById('name').selectedIndex='0';
Unfortunately this does not work at all. Should i change my javascript code? Or chrome extension?

Angular child form field validation

I have some existing code that's structured more or less like this:
<!-- my-form.html -->
<form ngNativeValidate>
<my-other-component></my-other-component>
<button mat-button type='submit'>Submit</button>
</form>
<!-- my-other-component.html -->
<input name='native-input' required />
<mat-form-field>
<mat-select name='balls' required>
<mat-option value='a'>a</mat-option>
<mat-option value='b'>b</mat-option>
<mat-option value='c'>c</mat-option>
</mat-select>
</mat-form-field>
The problem: while the native input is validated correctly — the browser displays a "Please fill out this field." prompt upon submission when needed — an empty input to balls is happily accepted.
The ngNativeValidate behavior of showing generic/non-descriptive errors only upon submission is fine for now, and we don't have time to convert everything into an Angular form with custom validation messages, so that isn't an option. What I'm looking for is a way to switch from native validation to Angular validation with the least possible effort to maintain an acceptable UX — e.g. simply disabling the submit button until the form input is valid.
As per angular.io/guide/form-validation, I see that I can change ngNativeValidate to #myForm='ngForm' and add [disabled]='myForm.invalid' to the submit button. However, this validation is only applying to form fields directly within my-form.html, not the ones in my-other-component.
Documentation here is really sparse, so I'm not sure what to try next. Does anyone know if it's possible to configure ngForm to validate those descendant components' form fields?
If you want to use template driven form approach then you have to import FormsModule into your #NgModule and apply NgModel directive to all your controls
<input name='native-input' ngModel required />
^^^^^^^
<mat-form-field>
<mat-select name='balls' ngModel required>
^^^^^^^
<mat-option value='a'>a</mat-option>
<mat-option value='b'>b</mat-option>
<mat-option value='c'>c</mat-option>
</mat-select>
</mat-form-field>
Now your child component should be aware about parent form. In order to do that you need to provide ControlContainer token within viewProviders array:
#Component({
selector: 'my-other-component',
template: `
...
`,
viewProviders: [ { provide: ControlContainer, useExisting: NgForm } ]
})
export class MyOtherComponent {
Ng-run Example
See also:
Angular2 nested template driven form

Categories

Resources