How to make an expandable list from a string array in Angular? - arrays

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

Related

How to get the expanded row value in react-table?

I have created a react-table in Material UI. Here I got a task like expanding the row. I did that expansion functionality But I don't know how to get the expanded value over there.
Here is the working demo.
Please tell me how to get the expanded row value in that. Like that entire row object
The row object should be under row.original. You can try something like this to test it:
{
row.isExpanded ? (
<tr>
<td>
{`hello ${JSON.stringify(row.original, null, 2)}}`}
{console.log("originalObj === ", row.original)}
</td>
</tr>
) : null;
}
The above code won't look pretty when rendered, but it should help you achieve your goal :)

Check if a row already exists before pushing it to table

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)

Using smart-table sorting by dynamic map value

I have a table to show records. One of it's columns contains select, to choose the version of the record. The second one is the map of dates, where keys are the versions. This looks like this:
<td><select ng-model="record.currentVersion"> ...</td>
<td>{{record.dates[record.currentVersion]}}
I'd like to add sorting by the second column's value, but I'm not sure how to address object's own property in st-sort. Something like st-sort="dates[currentVersion]" doesn't work. Is this possible to do?
Define a new function:
$scope.getDate = function(record) {
return record.dates[record.currentVersion];
};
Use st-sort:
<th st-sort="getDate">Date</th>
Demo: http://plnkr.co/edit/l6poIsZ2YHUyeFf4TdET?p=preview

Two way data binding with dynamic table and angularjs?

I am creating a table where I will have dynamic row creation. Everytime user clicks a button, a new row is created, as follows:
The second column will contain the amount of products. So, I'd like to sum all values from second column to display them with two-way data binding, using bg-model and ng-bind. Thus when user types in one, the valus will automatically update. I have no clue about it, in that the rows are dynamic!
For a fixed number of elements it works, but I dunno for a dynamic generation. Help?
We need to initially setup an object to use and perhaps put in some example data
$scope.ourTableArray = [];
$scope.ourTableArray.push({'textColumn': 'example text', 'valueColumn': 10});
Because of the way that Angular works with data-binding we can bind the ng-repeat of the table row to an array that will contain all of our values:
<tr ng-repeat="row in ourTableArray">
<td><input type="text" ng-model="row.textColumn"</td>
<td><input type="number" ng-model="row.valueColumn"</td>
</tr>
Next we need a way to add rows, so we can do that by creating a function to call on ng-click from some button. This will populate our $scope.ourTableArray following the format that was used in the first example value that we hardcoded in.
$scope.addRow = function(){
$scope.ourTableArray.push({'textColumn': '', 'valueColumn': 0});
}
Now that the ng-repeat is set up we just need to have a way to calculate the values. The solution to that is by creating a function to sum up our valueColumn from our object:
$scope.calculateTotal = function() {
var count = 0;
for(row in $scope.ourTableArray){
count += $scope.ourTableArray[row].valueColumn;
}
return count;
}
To output our new total all we have to do is call this function within our page.
Current Total of 2nd column: {{calculateTotal()}}
To summarize: Like I had stated above, because we have the ng-repeat binded to our array, anytime we modify the array (either by adding a row, removing a row, editing a rows values) it will be reflected immediately within the table. In addition, since we are outputting the results of our $calculateTotal() function, anytime we modify one of the values within our array it will also change.
Codepen Example
I think you can create a table of objects with ID, name and value and a function that will add new data on scope to it. Then you in your controller you can add function that will simply sum all values and one that will edit object from table by ID.
Next as ng-repeat in this table display it in view.
To all inputs in ng-repeat add function with sum and edit.
I did this in one of my projects but even if it works i don't think that's how it should be done. You can try it if you want.

add table data <td> only to one row on ng-repeat

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>');

Resources