Angular input and tab issues - html

I'm displaying a two dimensional array (Matrix) on the screen as separate input fields.
When I type a number for example "35", "3" is displayed on the screen, the cursor disappears and the "5" is not displayed at all.
What am I doing wrong?
Here is the definition of the matrix in the .ts file - matrix: string[][] ;
It could also be defined as a number but the behaviour stays the same.
Here is the HTML code
<span *ngFor="let row of matrix; let r = index">
<p></p>
<span *ngFor="let cell of row; let c = index">
<input type="text" [(ngModel)]="matrix[r][c]" maxlength="3" size="3">
</span>
</span>
removing "maxlength="3" size="3"" does not change the behaviour.
on the screen I get something like this;
1 2 3
4 5 6
7 8 9
If I want to replay the "1" with 35 after clicking 35 I get
3 2 3
4 5 6
7 8 9
Thanks
Moshik

Because you are using [(ngModel)], this is so called "2 ways bindings" in angular, so when you enter a value into the input, it will also update your matrix variable.
By default, with ngFor, when you change the collection (matrix in this case), it doesn't know what value changed, so it updates the whole thing => re-render the whole template => the input lost focus => you can only enter 1 value at a time.
To fix this issue, we make sure that Angular knows exactly what value is getting updated. And Angular provides us the trackBy function
A function optionally passed into the NgForOf directive to customize
how NgForOf uniquely identifies items in an iterable.
I also provide another way, which is clone your matrix to another variable, use this variable to display in the template, while all the changes are made in the matrix itself. In the link below I named that variable "display". You can see both implementations. The recommended way is ofcourse using the TrackByFn as it built-in and doesn't require another duplicated variable.
https://stackblitz.com/edit/angular-ivy-neezfj?file=src/app/app.component.html

Related

Is it possible in Angular to display a value in an option but return an array to the ngModelChange?

I am trying to organize a drop down list that will display a single value to the user but will also pass back an array object upon changing the selection.
Currently I have an array called classificationresult that has 3 elements CLASSIFICATION_NAME, GROUP_ID, GROUP_NAME.
When a user selects a particular CLASSIFICATION_NAME I want to pass back the entire array result containing all 3 elements listed above.
Currently the code below works for everything EXCEPT showing the CLASSIFICATION_NAME in the drop-down box upon loading. It shows the list once you click, but it starts with a blank until it is clicked. Any way to fix this? I believe the display element is tied to [ngValue] but that is also what I am using to pass back the entire array versus just the one.
Any help would be greatly appreciated.
<p>Select Classification*</p>
<select [(ngModel)]="selectedClassification (ngModelChange)="changedClassification($event)">
<option *ngFor="let classificationresult of classificationresults" [ngValue]="classificationresult" >{{ classificationresult.CLASSIFICATION_NAME }}</option>
</select>
Summary -- I want my drop down list to always have a value shown to the user (value being the Classification Name) but when one is selected I want the entire array to pass to the changedClassification function. Also sometimes after a user selects from other drops down on this page they will also go blank, but if they are selected a second time they will populate.
If everything is working as you are expecting except the initial value being displayed, I wonder if you need a [compareWith] function. I don't know what your classificationresult model looks like, but if I had to take a guess, putting a [compareWith] function on your <select> element would fix the issue.
Here is an article explaining it a little more.
I made this Stackblitz as an example with using the [compareWith] function. In my demo I am using ReactiveForms, but the compareWith should still be the same.
For your code, it may look something like:
<p>Select Classification*</p>
<!-- add this [compareWith] -->
<select [compareWith]="myCompareFunc" [(ngModel)]="selectedClassification" (ngModelChange)="changedClassification($event)">
<option *ngFor="let classificationresult of classificationresults" [ngValue]="classificationresult" >{{ classificationresult.CLASSIFICATION_NAME }}</option>
</select>
In your .ts file:
export class YourComponent {
// all your component code..
/* compare function, change the logic to fit your needs */
myCompareFunc (classificationRes1: any, classificationRes2: any): boolean {
return classificationRes1 && classificationRes2
? classificationRes1.CLASSIFICATION_NAME === classificationRes2.CLASSIFICATION_NAME
: classificationRes1 === classificationRes2
}
}
If that doesn't fix your issue, you may need to post more of your .ts code and data models.

Button click on a table Cell doesn't return the function value to only first row

I am new to react and html, we are currently developing a front page where in user can key in some values and based on which REST API (basically a backend service) would return the result.
We are capturing this result onto a table with 7 columns.
Last column i.e., column 7 will have a button which on a click, will invoke another REST API with different params and result, should display a value and also give another button option.
Currently I have below 2 issues:
1) When I click the button on any row, always the text is being displayed only on column 7 of row 1 (even though my state variables show correct results). Not sure what might be the issue. Can someone please point it out?
Code of column 5:
<td>
<className='xx' id='clm5'>
<button className='yy' type='submit' value={identifier of the row} onclick=this.function()> Display</button>
<p id='clm5' />
</td>
Function:
document.getElementById('clm5').innerHTML = Text to display;
2) I need to have an additional reload button along with text as stated in point 1. How can I get this achieved?
Any help over these is much appreciated

How to add an offset to an index in a *ngFor angular directive?

I want to display some data from a json but i can't simply add an offset to the index and show all te data from a certain offset but get
ERROR TypeError: Cannot read property 'id' of undefinedand the text in the div doesn't appear.
I have already tried to directly add a fixed number in the html file and it works (see the code below). But when it comes to use a variable "offset" (type:number) from typescript that is supposed to be updated with an input, the return type becomes undifined and the error appears. I also tried to use a method in my typescript file instead of doing the addition in the html file, and return the new index but it doesn't work and show the error. I also tried to call the method using {{addition(i,offset)}} and put the result in a variable that I use as an index but it still showing the error.
For exemple, this html file is working fine :
<ng-container *ngFor="let article of data; let i = index">
<ng-container *ngIf="i<(nbElements)">
<div (click)="checkArticle(data[(i+3)].id)">
<p class="text-center"> {{data[(i+3)][dataKey]}}</p>
</div>
</ng-container>
</ng-container>
The div reacts to my click and the text appears.
However, this html file is not working, even if the offset is set as 3 (as the html above) using an input in the parent component :
<ng-container *ngFor="let article of data; let i = index">
<ng-container *ngIf="i<(nbElements)">
<div (click)="checkArticle(data[(i+offset)].id)">
<p class="text-center"> {{data[(i+offset)][dataKey]}}</p>
</div>
</ng-container>
</ng-container>
The error appears.
The offset (type:number) is defined in my typescript file this way, and is changed by the parent component and can easily be displayed by the child component using console.log(offset):
export class AppColumnComponent implements OnInit {
#Input() offset : number ;
I expect the output to be texts showing the articles of my data json, but as I change the offset using an input like that data[(i+offset)] the result is an error, maybe it's impossible to use an other index using an other variable that a fixed number ?
Thank you for your support, it's my first post on stackoverflow i hope i did it well ! :)
If you want to make a pagination component, you should not rely solely on your HTML and some bindings.
Your component should have an "advanced" logic, in the sense that it should be able to know when it reaches the end/start of the collection (among other things).
Basically, this goes as follow :
Get the full collection (let's say 100 items)
Splice it to your item per page number (let's say 10, so results range is 0-10)
Test if items exist before the range
Test if items exist after the range
Allow/block page changing based on those variables.
This leaves you with
1 variable for the collection
1 variable (or 1 pipe) for the subset of the collection
1 variable for the items per page number
1 variable for the offset
2 booleans to disable pagination buttons.
Try working with this, and if you still have issues, then please provide a stackblitz with what you have tried !
You are accessing an index out of bounds.
data[(i+offset)] will be undefined for the last offset amount of elements in your data array so you are basically trying to do undefined.id which leads to your error.
You should change your method signature to only recieve the index as parameter and handle that case in your component.ts file

format number in input box with two decimal place

I have below input control in my html
<input id="inputcntrl" type="text" value="{{(mynumber) | number:'2.2-2'}}" [(ngModel)]="mynumber" (blur)="validatemynumber()" />
As you can see I am formatting input text to make sure it has two decimal values. It does work correctly when user enters the value in input box. onBlur event I am checking the value entered by user and if it is not within the range (min >mynumber>max) then I am setting mynumber with min value. Problem is mynumber displays min value with no formatting. forex: If min valule is 10 then input box should display 10.00 but it displays only 10..any idea how can I fix this? I am using angular2
Update: I think problem in my case is with somehow related to binding..When I update mynumber from my component and the new value is reflected in UI but its formatting is lost. mynumber variable is of type number. I need to find a way to update value with formatting from component
Try mynumber.toFixed(2)
<input id="inputcntrl" type="text" value="{{mynumber.toFixed(2)}}" [(ngModel)]="mynumber" (blur)="validatemynumber()" />
Here is a reference documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed
If you want to format mynumber at your component with an angular way, try using built-in DecimalPipe at your component(the same as number pipe used at your template).
import { DecimalPipe } from '#angular/common'
this.mynumber = this.decimal.transform(this.mynumber, '2.2-2');
Plunker demo

How to create a calculator that has 3 drop-down lists instead of buttons?

I want to create a calculator, in HTML, that has 3 drop-down lists and 3 sets of 6 fields.
I created a simple calculator a few years ago that had fields instead of buttons.. but I forgot how I made it.
The idea is to have 3 drop-down lists with 17 options each and a value for each option(some options will have up to 3 values). I want them to show the value/s, when selected, in specific fields of the 6 fields in set1, set2 will be a input set of fields and set3 will show the sum of set1 and set2.
If it can't be done in HTML only, It would be OK if there were input fields, aswell, instead of drop-down lists, here, the user would input a specific text, case sensitive, that might have 3 values which will have to appear in 3 specific fields(out of the 6 fields from set1(say field 1, 3 and 4) and some values will have to add up to some values already in whichever field.
I hope it is understandable.
You need the HTML element: http://www.w3schools.com/tags/tag_select.asp
To process, you'll either need javascript or some server-side programming language to process. Depending on what technology you use, there will be a different way of handling the selected values. You may want to look into jQuery's (javascript-based) methods of form handling documentation: http://api.jquery.com/category/forms/