I have a material tab component (mat-tab-gruop), and i needed a search bar inside the mat-tab-header, so i added a disabled tab containing only a mat-tab-label, and placed it inside it my search bar component.
Like this:
<mat-tab-group>
<mat-tab disabled>
<ng-template mat-tab-label>
<search-bar></search-bar>
</ng-template>
</mat-tab>
</mat-tab-group>
My problem is when I press an arrow key, instead of moving the cursor between characters, the focus changes to the other headers.
That happened because angular-meterial use Keyboard interaction to move focus between tabs.
I want to disable this Keyboard interactions behaviour, and keep focus on my search bar. I know I can move back focus after losing it to another tab header, then back to the search tab-header, using binding to (selectedTabChanged) and move focus back. I want the focus to always stay on the search bar input, so I’ll be able use arrows to move between charcters.
stackbiltz Example
my code:
<mat-tab-group [selectedIndex]="'1'">
<mat-tab disabled>
<ng-template mat-tab-label>
<div>
<mat-form-field>
<input matInput class="search" [value]="searchText">
</mat-form-field>
</div>
</ng-template>
</mat-tab>
<mat-tab label="tab1">
<p>some content</p>
</mat-tab>
<mat-tab label="tab2">
<p>some content</p>
</mat-tab>
</mat-tab-group>
Stop the key events propagating from the input field to stop them reaching the tab widget
<mat-form-field>
<input matInput class="search" [value]="searchText" (keydown)="suppressKeyEvent($event)">
</mat-form-field>
and
export class TabGroupAnimationsExample {
suppressKeyEvent (event:any) {
event.stopPropagation();
}
}
https://stackblitz.com/edit/angular-xufnk7-keqvdt
Just picking up angular and had to do something similar to above, so if anyone knows of a more 'angurly' way to do it (i.e. can you write the key suppression as some kind of imported module/directive?) that'd be kewl.
Related
I have been asked to do this project using Angular in work and honestly not touched Angular 2 before. I can do this no issue using jQuery but I am having trouble getting it to work in Angular. Basically, in this modal I have a form, and it is just a template in which you can choose what information you want to include within an email. I have a mat-select dropdown and depending on what has been selected, I want to then append that to the text area below on click of the check icon.
Example: "Hello {{Client Name}}, we are happy to be working with {{Company Name}}".
The values inside the '{{ }}' are the options selected in the mat-select above.
I will include my code below but unfortunately it isn't a lot to go off due to not being too sure where to start.
Component.html
<div fxFlex>
<mat-form-field fxFlex="90" appearance="outline">
<mat-label>Placeholder</mat-label>
<mat-select id="placeholderValue" matInput required>
<mat-option value="name">Client Full Name</mat-option>
<mat-option value="phone">Client Phone Number</mat-option>
<mat-option value="email">Client Email Address</mat-option>
<mat-option value="companyName">Company Name</mat-option>
</mat-select>
</mat-form-field>
<mat-icon fxFlex="10" fxLayoutAlign="center center" (click)="addPlaceholder()">check</mat-icon>
</div>
<mat-form-field appearance="outline" class="textarea">
<mat-label>Message</mat-label>
<textarea id="placeholderText" matInput formControlName="Description"></textarea>
</mat-form-field>
Component.ts
addPlaceholder(){
}
I apologise for the lack of code, I have been working on this regarding the UI and then this for the past few days, have been looking around for a way to do it and tried to convert my way in jQuery over to Angular and am assuming I could use some form on (change) function?
Here is an image of how it needs to look (multiple selects can be chosen so it also cannot replace the current select in the textarea).
I would appreciate any advice or help given. Thank you in advance.
I suggest you to lookup at angular two-way binding property.(https://angular.io/guide/two-way-binding).
To change dinamically the value of the select you can use [(ngModel)] used like this:
<mat-select id="placeholderValue" [(ngModel)]="variableName" matInput required>
<mat-option value="name">Client Full Name</mat-option>
...
</mat-select>
The variable will be updated automatically every time you change the selected value on the select field.
Another way to implement this could be to use (selectionChange) event on the mat-select field and link a function that will be executed after every change on the select value.
public myFunction(event: any) {
this.myVariable = event.value;
// other code that you need
}
<mat-select id="placeholderValue" (selectionChange)="myFunction($event)" matInput required>
<mat-option value="name">Client Full Name</mat-option>
...
</mat-select>
To output your variable in the html template you could use string interpolaion (https://angular.io/guide/interpolation).
To dinamically change the html structure you could use the *ngIf directive (https://angular.io/api/common/NgIf).
I have a dialog component which shows when I click an 'Edit' button next to an item in a table. The dialog component looks like this for now:
<h1 mat-dialog-title>{{item.ID}}</h1>
<div mat-dialog-content>
<p>Edit item</p>
<mat-form-field appearance="outline" style="justify-content: center;">
<mat-label>ID</mat-label>
<input matInput [(ngModel)]="item.ID">
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Name</mat-label>
<input matInput [(ngModel)]="item.Name">
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Date</mat-label>
<input matInput [(ngModel)]="item.Date">
</mat-form-field>
</div>
<div mat-dialog-actions style="justify-content: center;">
<button mat-button (click)="onNoClick()">Cancel</button>
<button mat-button [mat-dialog-close]="item.ID" cdkFocusInitial>Save</button>
</div>
This looks and works fine, and serves its purpose. But now I have several other tables with different types of data, and while I can create a separate dialog for each table and add the form fields manually for each type, I would like to have a more flexible solution.
How can I create a dialog where form fields are added based on the reference element's type?
E.g: If I have an object of type 'Fruit' in one table with properites like 'Name', 'Color', 'Price', and an object of type 'Car' with properties like 'Name', 'Manufactured', 'Horsepower', can I use the same dialog component and create the form dynamically?
Of course it is possible to make a single universal dynamic form, but it will become too difficult. As soon as there will be a need for logic for only one type of object (for example to disabling field "a" if a certain value in field "b" is selected).
Right now I'm working on an Angular project and in this project there's a page with 2 mat-autocomplete components, one for selecting country and the other for selecting state. The state one works fine with everything staying at expected places, as shown here:
And inspecting elements shows properties that make sense. For div with class name cdk-overlay-pane (highlighted in pic) the width is 350px and top as well as left will change dynamically to make it always display right above or under the associated input element.
And here's the related HTML code:
<div class="p-10" fxFlex.gt-md="100" fxFlex.gt-xs="100" fxFlex="100" [hidden]="!showStateDropdown">
<div class="spec-form-field drop-down" matAutocompleteOrigin #stateOrigin="matAutocompleteOrigin">
<mat-form-field>
<input type="text" #stateInput [formControl]="form.controls['state']" placeholder="{{ 'account_section.state' | translate }}" matInput [matAutocomplete]="state" (keyup)="isSelectedState = false; _filterSearch('state');" (blur)="removeUnusableValue();" (focus)="_filterSearch('state');"
[matAutocompleteConnectedTo]="stateOrigin">
<i class="material-icons">arrow_drop_down</i>
</mat-form-field>
<mat-autocomplete #state="matAutocomplete" (optionSelected)="isSelectedState = true;" (blur)="updateAccountData()">
<mat-option *ngFor="let state of states" [value]="state.iso">
{{ state.name }}
</mat-option>
</mat-autocomplete>
</div>
</div>
However, things get weird when it comes to the mat-autocomplete for country.
The dropdown for this one will always appear on the top left corner of the window (browser).
And when I'm inspecting elements, width, top and left properties of cdk-overlay-pane are always set to 0px.
However, I'm unable to find actual differences between the one for country and the one for state, except that everything that says "state" is replaced with "country" in the one for country. Here's the HTML code:
<div class="p-10" fxFlex.gt-md="100" fxFlex.gt-xs="100" fxFlex="100">
<div class="spec-form-field drop-down" matAutocompleteOrigin #countryOrigin="matAutocompleteOrigin">
<mat-form-field>
<input type="text" #countryInput [formControl]="form.controls['country']" placeholder="{{ 'account_section.country' | translate }}" matInput [matAutocomplete]="country" (keyup)="checkKeycode($event.keyCode,'country');" (blur)="removeUnusableValue();" (focus)="_filterSearch('country');"
[matAutocompleteConnectedTo]="countryOrigin">
<i class="material-icons">arrow_drop_down</i>
</mat-form-field>
<mat-autocomplete #country="matAutocomplete" (optionSelected)="changeCountry()" (blur)="updateAccountData()">
<mat-option *ngFor="let country of countries" [value]="country.iso">
{{ country.name }}
</mat-option>
</mat-autocomplete>
</div>
</div>
I honestly have no idea why the country one is not working properly. Everything seems fine but the end result is not.
Here's version numbers of components and modules being used in this project in case anyone wants to take a look.
Any help is appreciated.
Right after completing the post I just double checked the HTML file and found a different component with the same #countryInput at the bottom of the HTML file. Looks like whoever modified that file forgot to differentiate it from the original one. I'll just leave this question as a reference.
I need to insert a bunch of blue hyperlinks inside an accordion. So when we click the title, the expansion area that appears would contain a couple lines that call some function.
I've attempted to follow the example on the Angular Material website:
https://stackblitz.com/angular/ybovddobxlj?file=app%2Fexpansion-overview-example.html
I've modified expansion-overview-example.html to the following:
<mat-accordion>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
ALL FILES
</mat-panel-title>
</mat-expansion-panel-header>
<div> <!-- To put them on separate lines -->
<mat-form-field>
<label title="File 1" onclick="openFile1()"></label> <!-- THIS LINE BREAKS THE PAGE. HELP? -->
</mat-form-field>
</div>
<div> <!-- To put them on separate lines -->
<mat-form-field>
<label title="File 2" onclick="openFile2()"></label> <!-- THIS LINE BREAKS THE PAGE. HELP? -->
</mat-form-field>
</div>
</mat-expansion-panel>
</mat-accordion>
First of all, remove the mat-form-field, it is not required if you just want a simple link in the accordion (this is actually what breaks your code).
Just add a simple p tag with a (click) event handler (it is not onclick in Angular). This should do the trick:
<div>
<p (click)="openFile1()">File 1</p>
</div>
If you want to use label instead, use it like this:
<div>
<label (click)="openFile2()">File 2</label>
</div>
It should have a value, otherwise it is not visible and you can't click it.
Here
is a stackblitz with your sample code edited to make it work.
I have a form consisting of two tabs.
Based on an *ngIf, I decide what kind of tabs I want to show.
- If my form is a view, I want to see both tabs with labels (both tabs have information to show the user, second tab is results).
- If my form is an add, I want to see no tabs thus no labels.
I am not willing to create two separate files as I am trying to reduce my code as much as possible.
I tried adding an ng-template that replaces the mat-tab-label, but instead of removing it, my label is empty.
So far, this is what I have. My question would be: is it possible to remove the whole tab label without creating a new file and if yes, how can I?
<mat-dialog-content class="ManageTask">
<form [formGroup]="form">
<mat-tab-group mat-stretch-tabs>
<mat-tab>
<ng-template *ngIf="isView()" mat-tab-label>Task details</ng-template>
<div class="left">
<mat-form-field class="full-width">
<input matInput type="text" placeholder="Name" formControlName="name">
<mat-error *ngIf="form.controls['name'].hasError('required')">Name required</mat-error>
</mat-form-field>
<br/>
<mat-form-field class="full-width">
<textarea matInput type="text" placeholder="Description" formControlName="description"></textarea>
<mat-error *ngIf="form.controls['description'].hasError('required')">Description required</mat-error>
</mat-form-field>
</div>
</mat-tab>
<mat-tab *ngIf="isView()" label="Task results">
<div>...MORE CONTENT...</div>
</mat-tab>
</mat-tab-group>
</form>
I'm not sure if I understand the question.certainly you can do it.the correct way to use <ng-template>andngIf like this:
<ng-template [ngIf]="isView()">
<mat-tab label="Task details">...</mat-tab>
</ng-template>
or :
<mat-tab *ngIf="isView()" label="Task details">...</mat-tab>
differences between [ngif] and *ngif:Angular Structural Directives
hopes it help