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.
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).
I have a problem with the Forms Module of Angular Material!
I try to create a tag with many Angular Material Basic Inputs.
But on the website, only one Input field appears. The other input fields only show the value of the field. Now, when i click on the first input field, then the other fields appear correctly, but only when i click on the first input field?
Before i clicked on the first input field
And after
<form class="example-form" style="margin-top: 15px">
<mat-form-field class="example-full-width">
<mat-label>Favorite food</mat-label>
<input matInput placeholder="Ex. Pizza" value="Sushi" disabled>
</mat-form-field>
<mat-form-field class="example-full-width">
<mat-label>Favorite food</mat-label>
<input matInput placeholder="Ex. Pizza" value="Sushi" disabled>
</mat-form-field>
</form>
It seems that in your case, there might be some render errors. I suspect this as you have a disabled button in the template, but on your screenshots they do not appear to be so.
Check you Browser console. (F12 o CTRL+SHIFT+i) If you refresh your app, can you see any errors? Those can make the app work in undeterministic ways. In the command line, where your run ng serve do you see any errors maybe? Fix these first, and try again.
Problem Statement
I am trying to get the input from an <input> tag and display it as chips in the GUI, but the console gives me the error: "TypeError: this._chipList.registerInput is not a function".
Code
<mat-form-field>
<h3 class="sizeHeading">Add a size</h3>
<input matInput [matChipInputFor]="sizes" (matChipInputTokenEnd)="addSize($event)" <= Crash happens here
[(ngModel)]="data.size" class="sizeInput"><br><br>
</mat-form-field>
.... <!-- More code here but it is not part of the problem and what I am trying to show -->
<!-- Sizes display as chips -->
<div *ngIf="!displayOptions">
<mat-chip-list>
<mat-chip #sizes *ngFor="let size of sizes" [removable]="removable"
(removed)="removeSize(size)">
{{size}}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
</mat-chip-list>
</div>
Explanation of Code
In the top block of HTML code, I am trying to get user input and display it as chips in the GUI, and that is done in the bottom block of HTML code.
As you can see, and I think this is the problem but I am not sure, is that the [matChipInputFor]="sizes" in the input tag is supposed to point to the #sizes element in the bottom block of code to show where to output the input. And indeed, the line where the program crashes is the line of code where I specify [matChipInputFor]="sizes" in the input tag.
What I've tried
I have Googled and it seems that this error is not showing up in the results or anywhere on Stackover Flow.
I have tried placing the top block of code within the div tag with the *ngIf condition but to no avail. I did this because I thought that maybe this is a problem with the scope of the #sizes element.
Actual Results
The program crashes with the error, "TypeError: this._chipList.registerInput is not a function" and I cannot take the input and display it as chips.
Expected Results
I want to take the input and display it as chips in Angular Material.
There are two problems with your code.
The #sizes reference attribute is conflicting with your sizes array. You could name it #sizeList, for example.
The [matChipInputFor] reference has to point to the chip list (mat-chip-list), not the chips themselves. So you should move the #sizeList to your mat-chip-list element.
So it should look something like this:
<mat-form-field>
<input matInput [matChipInputFor]="sizeList" (matChipInputTokenEnd)="addSize($event)" [(ngModel)]="data.size" class="sizeInput"><br><br>
</mat-form-field>
<div *ngIf="!displayOptions">
<mat-chip-list #sizeList>
<mat-chip *ngFor="let size of sizes" [removable]="removable" (removed)="removeSize(size)">
{{size}}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
</mat-chip-list>
</div>
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