I have a html table
<table>
<tr ng-repeat="row in rowsproductrequests">
<td>{{row.PRODUCTID}}</td>
<td>{{row.DESCRIPTION}}</td>
</tr>
</table>
a second table for search products :
<table>
<tr ng-repeat="row in searchproductsList">
<td>{{row.PRODUCTID}}</td>
<td>{{row.DESCRIPTION}}</td>
</tr>
</table>
On click I am pushing the item from the search table (Second table) to the main table (first table) :
JS:
$scope.addItemAsIng = function(row){
$scope.rowsproductrequests.push(row);
}
The items are pushed. My problem is how can I check if an item exists in the first table so I can stop pushing the same item twice.
Use includes, for example:
$scope.addItemAsIng = function(row){
if(!$scope.rowsproductrequests.includes(row)) $scope.rowsproductrequests.push(row);
}
An alternative approach
Rather than populate the second table by pushing selected items to a second array, I'd suggest using the same array but send it through a custom filter that identifies which items are selected.
How to do it
1) Create a function in your controller that sets the selected property of a given object to true:
$scope.onAvailableRowClicked = function(row){
row.selected = true;
}
2) Then wire that up to the first table (of available objects) using the ng-click directive:
<h4>Available</h4>
<table>
<tr ng-repeat="row in rowsproductrequests"
ng-click="onAvailableRowClicked(row)">
<td>{{row.PRODUCTID}}</td>
<td>{{row.DESCRIPTION}}</td>
</tr>
</table>
3) Now create a custom filter that identifies all of the objects within a given array that have the selected property set to true:
app.filter("isSelectedFilter", function() {
return function(input){
return input.filter(function(obj){
return (obj.selected === true);
});
}
});
4) Finally, use the filter in the ng-repeat of the second table to identify selected records:
<h4>Selected</h4>
<table>
<tr ng-repeat="row in rowsproductrequests | isSelectedFilter">
<td>{{row.PRODUCTID}}</td>
<td>{{row.DESCRIPTION}}</td>
</tr>
</table>
Benefits of this approach
You only have to maintain one array. Less variables means that your code becomes easier to read, you can see more easily what is driving the view. It's also easier to debug if things go wrong.
There's only ever one instance of each object. One source of the truth means that there's no danger of objects falling out of sync ("should I use this or that!?!?"). It also means that it's not physically possible to select an object more than once.
You can easily reuse the selected property in other parts of the view. If you wanted to highlight in the available list which objects had been selected, you could do so easily using ng-class for example. (The thought of using array comparison logic here is already giving me a headache!)
Demo
CodePen: A custom filter to identify selected records
Approach One: One solution will be once you add the row from the second table, remove that item from the collection and add to the first table that,s how you will never get duplicate items.
Second Approach: you will have to maintain an identity column in both tables based on these identity columns you need to check before adding whether this item exists.
Also you can use "indexOf()", it will return array index of your current item, if not exit it will return -1
Like
if($scope.rowsproductrequests.indexOf(row) != -1)
Related
In my .ts component file, I have
campaignList: string[]
I am populating this programmatically.
In my HTML file, I have
<table>
<thead>
//Headers
</thead>
<tbody>
<tr>
<td>
//Need to have a list of campaigns here
</td>
//Other fields here
</tr>
</tbody>
</table>
Now, the way I need my list displayed is like this:
When I click on the More button, I would want the list(and the whole row in the table) to expand and show me the list, changing into a Less button to revert the process. I am familiar with how to create buttons and have them change names, but I am not sure how I can create and add to a list using a variable string array.
Could someone please point me in the right direction for this?
Assuming your array of campaigns looks like
var campaigns = ['camp1','camp2','camp3','camp4','camp5','camp6','camp7','camp8'];
var countOfItemsToBeShown = 3;
//fills duplicate array with number of items you need to show on UI
var displayCampaigns = campaigns.filter((c,index) => index <= countOfItemsToBeShown);
//when someone clicks show more just replace with original array
function showMore(){
displayCampaigns = campaigns
}
function showLess(){
displayCampaigns = campaigns.filter((c,index) => index <= countOfItemsToBeShown);
}
In order to add to the existing variable string array, For each new item you want to add, push it like so: campaignList.push(item) - after you have created the array.
With regards to expanding the table row. there are different approaches you can take e.g give the row a fixed height. When the +more button is clicked. you can then override the fixed height in order to accommodate the extra content
I have two table, table 1 and table 2.. Table 1 has a field count. based on the count value(count value= no of rows populated), rows should be automatically populated in table 2. I am new to angularjs. Please let me know how can acheive this
To render values in your table you can use ng-repeat directive.
You can use things such the ngIf, ngShow and ngHide directive to hide or show DOM objects based on an expression, or use ngRepeat to dynamically add additional DOM object based on a growing or shrinking array in your controller.
My guess is you're looking for an visibility directive, so I think the following might help:
<table id="table1">
<tr data-ng-repeat="row in table1">
<td>{{row.someData}}</td>
</tr>
</table>
<table id="table2" data-ng-show="table1.length == 0">
<tr data-ng-repeat="row in table2">
<td>{{row.someData}}</td>
</tr>
</table>
Note that both tables are filled with an ngRepeat by using corresponding arrays from your controller as a source. On the second table, you can see an ngShow directive with an expression that says: "if table1 is empty, show me".
I hope this helps.
in a table with ng-repeat is it possible to add a cell only to one row?
in my code:
<tbody>
<tr ng-repeat="user in users ng-click="selectUser(user)">
<td>{{user.username}}</td>
<td><input type="text"....></td>
<td><input type="checkbox"...></td>
<td><input type="submit" ... ng-show="user==selectedUser" /></td>
</tr>
</tbody>
in this code I want the last td appears only on the selected row and does not affect other rows, is it possible? or it is JS or CSS thing ?
First off you should be using the controller as syntax, it automatically puts everything in the controller under 1 object, which can cause issues with Angular. But I don't think that's the issue here.
The user you select could be equal to the selectedUser, but if they aren't pointing to the same reference, they won't be able. If usernames are distinct I'd change the ng-show="user.username == selectedUser.username"
and that should work fine.
It is possible, it seems like your code is mostly correct, but you're using selectedUser as a function and as an object representation of user. Maybe your function would be called selectUser which would set $scope.selectedUser. ng-show="user == selectedUser" would make since then.
I'm personally not a big fan of having conditions in the view, so I'd have a function in the controller which does the comparison and returns true or false.
function isSelectedUser(user) {
return user == $scope.selectedUser;
}
then you can just use ng-show="isSelectedUser(user)"
Use JQuery to append the <td> on the selected row <tr>. The :nth-child() is an easy way for you to select a row.
var selectedRow = 2;
$('tbody tr:nth-child('+ selectedRow +')').append('<td><input type="submit" /></td>');
I'm working with angular building a table of data which comes from a JSON API call. I'm having to use a nested ngRepeat however I'm seeing strange results where whole table rows are missing when the row has a couple empty strings.
I can reproduce with the following plunk.
http://plnkr.co/edit/VCzzzPzfgJ95HmC2f83P?p=preview
<script>
function MyController($scope){
$scope.test = {"rows":[
["one","two","three"],
["one","two","three"],
["one","","three"],
["one","",""],
["","two",""],
["","","three"],
["one","two","three"],
["one","two","three"],
]};};
</script>
<div ng-app ng-controller="MyController">
<table>
<tr ng-repeat="(key,ary) in test.rows">
<td>{{key}}</td>
<td ng-repeat="value in ary">{{value}}</td>
</tr>
</table>
</div>
Notice when an array has two empty strings the nested ngRepeat appears to fail.
Am I going mad? Is there an explaination to this?
Yes. You would need to use track by $index since you are repeating primitives, or convert it to array of objects. Reason is ng-repeat creates unique id $$hashkey (and attached to the repeated object as property) for each of the iterated values if it is an object (unless you specify something as track by).
In your case you have primitives so it cannot attach a property itself, so it tries to consider the values repeated as identifier and it finds duplicate when you have multiple empty strings iterated. You would see the same effect when you repeat array of objects with more than one of them is undefined or null as well..
So in this case you can use track by $index So repeated items will be tracked by its index.
<td ng-repeat="value in ary track by $index">{{value}}</td>
Demo
Much better option always is to convert it to array of objects so you don't run into these kinds of issues. WHen you have a property that uniquely identifies the repeated element (say id) you can set it as track by property. When you rebind the array (or refresh the array) angular uses the tracked identifier to determine if it needs to remove the element from DOM and recreate it or just refresh the element that already exists. Many cases where a list is refreshed with the list of items it is always desirable to use a track by with an identifier on the object repeated for performance effectiveness.
I have the following code
<tr>
<th ng-click="predicate='-name'; reverse=false;">Name</th>
<th ng-click="predicate='age'; reverse=true;">Age<th>
<tr>
<tr ng-repeat="user in users | orderBy:predicate:reverse">
<td>{{user.name}}<td>
<td>{{user.age}}</td>
</tr>
My aim here is whenever i click on the table header, then the corresponding column has to be sorted based on particular predicate and reverse. And that is happening perfectly. But I have a scenario where, when i click on an external object, then my age value in table changes here and hence as a result the table sort order is getting disturbed. But i don't want sort to get disturbed. How can i skip table to not obey sort on other actions and have it only on click of table column headers? Can anyone help me with this?
I don't think this is possible. Whenever "users" changes, Angular will notice (since that scope property (i.e., "users") is bound (one-way data binding) to the ng-repeat directive), and Angular will update the view.