How to data-bind an array element with Angular - html

I am using Angular.
I have a table with two columns. Each cell of 1st column is a series number. Each cell of second column is a drop down of serial numbers. I am binding to a data source in my component and it is working fine.
My data source is a simple hard coded array in my component (I have as many elements as I like, here I show only one):
toolSeries = {
"Series": "12345678A",
"Serials" : ["123321", "123321", "54654", "357", "386758"],
}
and my binding is like so:
<tr *ngFor='let tools of toolSeries' height="50px">
<td class="tableEntryText">{{tools.Series}}</td>
<td class="tableEntryText">
<select class="noBorder additionalSelectStyle" name="filter_for" (change)="OnSerialChanged($event.target)">
<option *ngFor = 'let serial of tools.Serials'>
{{serial}}
</option>
</select>
</td>
<tr>
All good, works fine.
Now I need to add the following: each Tool Serial can have a "state". So I modify my data structure like so:
toolSeries = [
{
"Series": "12345678A",
"Serials" : ["199921", "123321", "54654", "357", "386758"],
"State": ["OK","BAD","BAD","UNKNOWN", "OK"]
},
So, I add another column to my HTML table and now my code becomes:
<tr *ngFor='let tools of toolSeries' height="50px">
<td class="tableEntryText">{{tools.Series}}</td>
<td class="tableEntryText">
<select class="noBorder additionalSelectStyle" name="filter_for" (change)="OnSerialChanged($event.target)">
<option *ngFor = 'let serial of tools.Serials'>
{{serial}}
</option>
</select>
</td>
<td class="tableEntryText">
<label class="labelAdjust">{{series.State[0]}}</label>
</td>
</tr>
Now as it stands, {{series.State[0]}} will mean that the the new field always shows the value of the first state for each serial.
Question: How should I write the binding so that the State of the field will reflect the state of the Serial selected in the drop down? So for example, when the user selects "123321" from the dropdown my new column's cell should show "BAD" instead of "OK".
Thanks for any help.

There are some other considerations here but the quick and dirty way to do what you want is this,
<select [(ngModel)]="selectedValue" class="noBorder additionalSelectStyle" name="filter_for" (change)="OnSerialChanged($event.target)">
<option *ngFor = 'let serial of tools.Serials' [ngValue]="serial">
{{serial}}
</option>
</select>
<td class="tableEntryText">
<label class="labelAdjust">{{tools.State[tools.Serials.indexOf(selectedValue)]}}</label>
</td>
You have to bind a value to your select so that you know what the selected option is and then you need to find the index of that value in the tools.Serials array and use that index in tools.State to get the corresponding state. You will also need to declare the selectedValue variable in your .ts file,
public selectedValue: number;
Keep in mind this assumes that tools.Serials and tools.State have the same number of elements. If they ever become out of sync you will likely have errors.
The better solution is likely to rethink your data structure and associate the states with their serials in a more direct way.

Stackblitz
My approach is quite similar to #DKidwell answer here, but instead of saving and looking up the value of selected tool.serial. I'm saving the index of selected tool.serial in ngModel & retrieving the tool.State value on same index if exists else there is no error and no value in tool.State.
So, even if the length of these arrays mismatched your code will work, but still probably its a good idea to rethink your data structure if this is going to be get more complex.
<select class="noBorder additionalSelectStyle" name="filter_for" [(ngModel)]="selectedSerial">
<option value="" disabled>Select a serial</option>
<option *ngFor = 'let serial of tools?.Serials; let i = index' [value]="i">
{{serial}}
</option>
</select>
</td>
<td class="tableEntryText">
<label class="labelAdjust">{{(tools?.State[selectedSerial]) || ''}} </label>
</td>
</tr>

Thank you both very much for taking the time to answer, I very much appreciate it. Your answers taught me a lot. In the end I did indeed change the data structure to one which enabled me to use less data-binding code.

Related

How to hide the null date[0001-01-01T00:00:00] value in view?

In my manager, I set the null value to date.but in view it shows the some value.I need to hide that date value.I tried if the created date is null, I showed empty data.but it comes with some value
Html:
<ng-template #tmplt>
<tr *ngFor="let manage of managecontent; let i =index">
<td>{{manage.CategorytypeName}}</td>
<td>{{manage.CreatedBy}}</td>
<td *ngIf="manage.CreatedDate!=null">{{manage.CreatedDate}}</td>
<td *ngIf="manage.CreatedDate == null"></td>
<td *ngIf="manage.DocumentDetails!=null">{{manage.DocumentDetails.DocName}}</td>
<td *ngIf="manage.DocumentDetails==null"></td>
<td>
<app-file-upload [documentModel]="manage.DocumentDetails" [isMultipleFile]="true" [model]="manage" (emitterFile)="fileSelect($event)"></app-file-upload>
</td>
</tr>
</ng-template>
First, you should use the *ngIf like this.
<td *ngIf="!manage.CreatedDate">{{manage.CreatedDate}}</td>
Second, you should use timestamps or date objects for your dates. Not strings.
Third, once you manage your dates with objects or timestamps, you can test them easily : either they have the value null, or their value is the start of the Unix time (maning the timestamp would be equal to zero). In both cases, those are falsy values, that you can test as I told you in the first point of my answer.
Maybe like this
<td *ngIf="!manage.CreatedDate; else elseBlock">{{manage.CreatedDate}}</td>
<ng-template #elseBlock> - </ng-template>

How do I filter Html table on default dropdown value on page laod in angularjs

This is my Select
<select class="viewcombobox" ng-model="search.view_nm">
<option ng-repeat="tab in CompetRx | unique:'view_nm'" value="{{tab.view_nm}}">{{tab.view_nm}}</option>
</select>
Dropdown value are Weekly & Monthly
This is my table
<table>
<tr> <th> Brand </th> </tr>
<tr ng-repeat="tab in CompetRx | filter:search.view_nm >
</table>
On intial page load how do I set Weekly as default value in Dropdown at same time it should filter the table accordingly
Immediate help is appreciated!!
It looks like you didn't initialised your search object.
$scope.CompetRx =[{view_nm: "Weekly"}, {view_nm: "Monthly"}]
$scope.search = {view_nm: "Weekly"}
I created small working plunker. Hope it will help.

Angular UI-Bootstrap typeahead in table

Simple question really, but how can I setup the typeahead to work in a table that works off of a different table than my typeahead?
For Example, I have a foreign key in a table and I want to let the users select this key based on the respective NAME value in the foreign key's primary table.
Code Example:
<table class="table table-bordered table-hover table-striped rwd-table" id="page-wrap">
<thead>
<tr>
<th>Primary ID</th>
<th>Foreign Key (As Name)</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="p in PrimaryTable" id="display">
<td data-th="ID">{{p.PrimaryID}}</td>
<td>
<input id="ForeignKeyName"
type="text"
ng-model="p.ForeignKeyID"
uib-typeahead="f.ForeignKeyID as f.ForeignKeyName for f in ForeignKeyTable | filter:$viewValue"
class="form-control">
</td>
</tr>
</tbody>
With this example, I would want the users to see the "Foreign Key (As Name)" As the Name value instead of the ID value. The trick is that I also want the underlying value to be the ID and have it mapped to match the original value, as notified by the ng-model.
UPDATE: Another question I had that was in line with the previous one is how do I setup my ng-model to show the ForeignKeyTable.ForeignKeyName in place of the PrimaryTable.ForeignKeyID?
This would be similar ( I imagine) to how the uib-typeahead matches the ForeignKeyTable.ForeignKeyID and ForeignKeyTable.ForeignKeyName but with the two seperate tables?
What I would desire is to be able to put ng-model: PrimaryTable.ForeignKeyID as ForeignKeyTable.ForeignKeyName
First thing would be updating PrimaryKeyTable rows every time user selects value in typeahead. You'll have to catch selected item and manually assign its ForeignKeyId value to the row of PrimaryTable.
The way to do it is to add typeahead-on-select directive to your typeahead and bind it to the function that assigns the values for you.
It would look like this:
HTML
<tr ng-repeat="p in PrimaryTable" id="display">
<td data-th="ID">{{p.PrimaryID}}</td>
<td>
<input id="ForeignKeyName"
type="text"
ng-model="selectedItem" <!-- could be anything really for we will not use it here -->
uib-typeahead="f.ForeignKeyID as f.ForeignKeyName for f in ForeignKeyTable | filter:$viewValue"
typeahead-on-select="onSelect($item, $model, $label, p)"
class="form-control">
</td>
</tr>
Inside your controller
$scope.onSelect = function($item, $model, $label, primaryKeyTableRow) {
primaryKeyTableRow.ForeignKeyId = $item.ForeignKeyId;
}
Next step is to display name property value of ForeignKeyTable row that corresponds to ForeignKeyId from PrimaryKeyTable in each row. Since we have to filter ForeignKeyTable to find suitable item it would be a good idea to put that logic inside the controller. For there are multiple rows in which we want to display corresponding name, we'll have to filter the ForeignKeyTable for each row separately. This is where ng-controller for ng-repeat comes in handy. What we'll do is bind new controller for each table row generated by ng-repeat and put some logic inside that controller. In HTML it would look like this:
<tr ng-repeat="p in primaryKeyTable" ng-controller="itemController">
<!-- ... -->
</tr>
And we'll have to define new controller in JS file:
app.controller('itemController', function() {
// ...
});
Now we can have separate logic for each row in the table. So that's a place to filter ForeignKeyTable to find corresponding item and display it's name.
Since whole code is kind of big I've put it in the plunker:
http://plnkr.co/edit/xccgnpxoPHg6vhXWPwZn?p=preview
See what you can do with it.

Dropdown column in smart-table (angularjs)

I need to configure one of the columns in my smart-table to be a dropdown. The possible values for the 'Status' column are OK and PENDING. (These values are retrieved from a rest api) I am looking to initialize the value in the dropdown to OK/PENDING based on the value retrieved from the api.
I posted what I've tried so far,the status are all set to OK regardless of the actual value.
I'm just starting out with smart-table and javascript so any help is appreciated.
For reference, here is a sample json object being returned from my rest api (other fields removed):
[
{
comments: [
{
comment: "Test comment",
userId: "test_user",
timestamp: 1473282222280
}
],
status: "PENDING"
}]
Here is the smart-table html code:
<tbody>
<tr ng-repeat="row in rowCollection" ng-class="{danger: (row.status=='PENDING'),success:(row.status=='OK')}">
<td cs-select="row"></td>
<td align="center">
<select st-search="status">
<option value="">OK</option>
<option value="">PENDING</option>
<!-- <option ng-repeat="row in rowCollection | unique:'status'" value="{{row.status}}">{{row.status}}</option> -->
</select></td>
<td align="center">{{row.comments[0].comment}}</td>
</tbody>
and a screenshot of the table:
You can try with the ng-selected directive in this way:
<select>
<option ng-selected="row.status == 'PENDING'">PENDING</option>
<option ng-selected="row.status == 'OK'">OK</option>
</select>

setting up input type within ng-repeat

I have a list of list of input fields in options. Now, I am adding these input fields to my page using ng-repeat.
<input type="text">
I have their input types in the same options object which is repeating. These types are like this: String, Varchar, etc.
Now, I want to set type of input field according to the parameter type i have.
Here is what i want to do
<tr ng-repeat = "option in options">
<td><input type="text" ></td>
</tr>
I have a parameter named option.Paramtype which contains type of each input field. I want to set the type of input field as number if it is Int and so on.
Please help.
Given you have a array of options such as:
options = [
{Paramtype:'String', foo:25, bar:'Unicorn'},
{Paramtype:'int', foo:30, bar:'Kitten'},
{Paramtype:'Email', foo:28, bar:'Dragon'},
{Paramtype:'Date', foo:15, bar:'Kanye'}
]
Within your ng-repeat block you could use ng-if to check the Paramtype property and set the input type accordingly. Like so:
<tr ng-repeat = "option in options">
<td>
<input ng-if="option.Paramtype == 'String'" type="text">
<input ng-if="option.Paramtype == 'int'" type="number">
<input ng-if="option.Paramtype == 'Email'" type="email">
</td>
</tr>
Hopefully that helps
Otherwise if you could put an additional parameter into each element in your options array you could fill the input type using angular binding.
options = [
{Paramtype:'String', inputType:'text', bar:'Unicorn'},
{Paramtype:'int', inputType:'number', bar:'Kitten'},
{Paramtype:'Email', inputType:'email', bar:'Dragon'},
{Paramtype:'Date', inputType:'datetime', bar:'Kanye'}
]
<table>
<tr ng-repeat = "option in options">
<td><input type="{{option.inputType}}"></td>
</tr>
</table>
I'd simply suggest you to use ng-attr directive to set the value of type attribute dynamically, In order to make your implementation more cleaner, you should maintain one object that will have mapping of What Paramtype would be what input Type. Then we could use mappingOfTypes variable with its index to populate the type attribute value of input field.
Markup
<tr ng-repeat = "option in options">
<td><input ng-attr-type="{{mappingOfTypes[option.Paramtype]}}" ></td>
</tr>
Controller
$scope.mappingOfTypes = ["String": "text", "Int": 'number'];