turn off re-sorting in angularJS while editing - angularjs

I have an AngularJS app that lists a bunch of items in a table. Like this:
<table class='unstyled tmain'>
<tr>
<td ng-click='setSort($event)'>X</td>
<td ng-click='setSort($event)'>Desc</td>
<td ng-click='setSort($event)'>created</td>
<td> </td>
</tr>
<tr ng-repeat="item in items | orderBy:itemNormalizationFunction:sortReverse">
<td><input type='checkbox' ng-model='item.done'
ng-click='onCheckedChanged(item)'/></td>
<td><div edit-in-place="item.text"
on-save="updateItemText(value,previousValue,item)"></div></td>
<td><span class='foo'>{{item.created | dateFormatter}}</span></td>
</tr>
</table>
The table headers are clickable to set the sort order. The cell in the 2nd column in each data row is editable "in place" - if you click on the text it gets replaced with an input textbox, and the user can edit the text. I have a little directive enabling that. This all works.
The problem comes in while editing. Suppose I have it set to sort by "description" (the 2nd column). Then if I edit the description (via the edit-in-place directive), as I am typing in the input box, the sort order changes. If I change the first few characters, then angular re-sorts and the item is no longer under my cursor. Nor is it even focused. I have to go hunting through the list to find out where it got re-sorted to, then I can re-focus, and resume typing.
This is kinda lame.
What I'd like to do is tell angular to (a) stop re-sorting while I am keying in the input box, or (b) sort on a separate (not-displayed) index value that preserves the ordering before the edit began. But I don't know how to do either of those. Can anyone give me a hint?
I know this is sort of complicated so I'll try to put together a plunkr to show what's happening.

This is the plunkr that shows how I solved the problem.
http://embed.plnkr.co/eBbjOqNly2QFKkmz9EIh/preview

You can create custom filter and call that only when necessary. Example when you click on 'Grid header' for sorting or after dynamically adding/removing values to array, or simply click of a button(Refresh Grid)
You need to dependency Inject Angular filter and sort filter
angular
.module('MyModule')
.controller('MyController', ['filterFilter', '$filter', MyContFunc])
function ExpenseSubmitter(funcAngularFilter, funcAngularFilterOrderBy) {
oCont = this;
oCont.ArrayOfData = [{
name: 'RackBar',
age: 24
}, {
name: 'BamaO',
age: 48
}];
oCont.sortOnColumn = 'age';
oCont.orderBy = false;
var SearchObj = {
name: 'Bama'
};
oCont.RefreshGrid = function() {
oCont.ArrayOfData = funcAngularFilter(oCont.ArrayOfData, SearchObj);
oCont.ArrayOfData = funcAngularFilterOrderBy('orderBy')(oCont.ArrayOfData, oCont.sortOnColumn, oCont.orderBy);
}
}
and call in HTML something like:
<table>
<thead>
<tr>
<th ng-click="oCont.sortOnColumn = 'age'; oCont.RefreshGrid()">Age</th>
<th ng-click="oCont.sortOnColumn = 'name'; oCont.RefreshGrid()">Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="val in oCont.ArrayOfData">
<td>{{val.age}}</td>
<td>{{val.name}}</td>
</tr>
</tbody>
</table>

Related

ng-repeat dynamically create arrays for nested ng-repeats

Is it possible to have ng-repeat dynamically create arrays for nested ng-repeats?
I know this sounds silly, but I'm essentially looking for something like this, and hoping someone will tell me how terrible of an idea this is and present a better solution:
<tbody ng-repeat="row in myRows track by $index">
<tr>{{row.name}}</tr>
<tr ng-repeat="subRow in myRows$index>{{subRow.name}}</tr>
</tbody>
So the idea is that the first <tr> row actually has a button that will show the subRows once clicked. So once clicked (before it actually displays the rows), I'll create the array then, such as:
myRows0 = [{name:"Sub Row A", value:1},
{name:"Sub Row B", value:2}];
or if the second row was clicked, I'd create:
myRows1 = [{name:"Sub Row C", value:3},
{name:"Sub Row D", value:4}];
I'm assuming something like this won't work because ng-repeat needs to have the array created before it can create the DOM. Is that correct? But I'm not sure how else I'd be able to create something like this then using this table structure. Any help?
It is possible and in my opinion it is not a bad idea, for example you may want to load your subRow data only when user clicks on displaySubRow items if your subRow data is big or they are images, to avoid putting an unnecessary burden to your server or keep your users waiting.
Working Plunker
Sample Code
html
<table>
<tbody ng-repeat="item in data" ng-init="item.show = false">
<tr>
<td>
<button ng-show="item.show==false" ng-click="getRowSubItems(item)">Show</button>
<button ng-show="item.show==true" ng-click="item.show = false">Hide</button>
</td>
<td>
{{item.name}}
</td>
</tr>
<tr ng-show="item.show == true">
<td>
</td>
<td>
<div ng-repeat="subItem in item.cars">
{{subItem}}
</div>
</td>
</tr>
</tbody>
</table>
js
$scope.data =
[{"name":"Lex",
"age":43
},
{"name":"Alfred",
"age":30
},
{"name":"Diana",
"age":35
},
{"name":"Bruce",
"age":27
},
{"name":"Oliver",
"age":32
}];
$scope.getRowSubItems = function(item){
//you can also make a http call to get data from your server
item.show = true;
if(item.name == "Lex"){
$http.get('https://jsonplaceholder.typicode.com/posts/1')
.then(function(response) {
item.cars = response.data;
});
}
else{
item.cars = [ "Ford", "BMW", "Fiat" ];
}
}

Hide table rows in angular Js

I have a table, I am already given it CSS using ng-class if they satisfy a condition. Now I want to show only those rows who satisfy the same condition on a button click. I have wrote a controller which checks if the data received is within 24 hours are not and marks the data cell. Until this it's working.Now I need to add a button and show only the row which has this td marked as not received in time.
<tbody>
<tr ng-repeat ="data in log">
<td>{{data.UniqueId}}</td>
<td>{{data.Name}}</td>
<td ng-class ="{'data-notreceived' : dataNotReceived('data.receivedTime')}">{{data.receivedTime
}}
</tbody>
</table>
I think something like this should work. Basically, clicking the button will toggle between showing all or only the items marked as 'data not received'.
<tbody>
<tr ng-repeat ="data in log" ng-show="showAll || dataNotReceived(data.receivedTime)">
<td>{{data.UniqueId}}</td>
<td>{{data.Name}}</td>
<td ng-class ="{'data-notreceived' : dataNotReceived('data.receivedTime')}">{{data.receivedTime}}
</tr>
</tbody>
// in controller
$scope.showAll = true;
$scope.onButtonClick = function() {
$scope.showAll = !$scope.showAll;
return false;
}
From the information provided in question what I can say is: Use ng-show to show rows based on your condition.
<tr ng-show ="your_condition">
You could also use an ng-if rather than ng-show. See the differences here.
Really depends on how often the hide/show toggle needs to happen.
<tbody>
<tr ng-repeat="data in log" ng-if="showLast24Hrs(data.ReceivedTime)">
<td>{{data.UniqueId}}</td>
<td>{{data.Name}}</td>
<td>{{data.ReceivedTime}}</td>
</tbody>
and then in the controller,
$scope.showLast24Hrs = function(receivedTime){
if($scope.isLast24Hours) {
return receivedTime < 200; // Write your less than 24 hours check here
}
return true;
}
I wrote this demo on Codepen. Hope that helps.

Edit a filter with a simple checkbox

I would like to make an option for showing inactive users by checking a button.
Here is the users array:
$scope.users = [
{firstname: 'Paul', inactive: true},
{firstname: 'Mark', inactive: false},
{firstname: 'Maggie', inactive: false},
{firstname: 'Lucy', inactive: true}
];
And the table to display it:
<table>
<thead>
<th>Firstname</th>
<th>Activity</th>
</thead>
<tbody>
<tr ng-repeat="user in users | filter: ??">
<td>{{user.firstname}}</td>
<td>{{user.inactive}}</td>
</tr>
</body>
</table>
<input type="checkbox" ng-click="showInact()">Show inactives
I'm learning AngularJS, I didn't found an interesting way to do that. Can you help me finding a solution?
Thanks :)
Just do this way:
1) At you controller:
$scope.showInactive = false;
$scope.filterInact = function(item)
{
return item.inactive === $scope.showInactive;
};
$scope.showInact = function() {
$scope.showInactive = !$scope.showInactive;
}
2) Setup the filter:
<tr ng-repeat="user in users | filter:filterInact">
<td>{{user.firstname}}</td>
<td>{{user.inactive}}</td>
</tr>
I personally like using a filter function to filter data. This approach is flexible and can easily interact with your other form variables. From the angular docs, the filter expression can be a:
function(value, index): A predicate function can be used to write
arbitrary filters. The function is called for each element of array.
The final result is an array of those elements that the predicate
returned true for.
So an example filter function might look like this:
$scope.filterFunc = function (user) {
//if the checkbox is checked show everyone, else only those that aren't inactive
return $scope.showInactives || !user.inactive;
};
And the HTML would be changed to accommodate the filter function. Specifically, I'm binding the checkbox to a $scope variable ($scope.showInactives) that the filterFunc function uses in its logic. And of course the ng-repeat is using the function called filterFunc.
<input type="checkbox" ng-model="showInactives"/>Show inactive users
<br/>
<table>
<thead>
<tr>
<th>Firstname</th>
<th>Activity</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="user in users | filter:filterFunc">
<td>{{user.firstname}}</td>
<td>{{user.inactive}}</td>
</tr>
</tbody>
</table>
And if you need any other convoluted logic, the filter function allows you a lot of freedom. The only thing it needs to return is a boolean (true or false).
Demo.
Unrelated to filtering, I also had to fix the table's HTML by putting the <th> inside a table row <tr>.
Easiest Way !! You can set value of filter on click event.
<tr ng-repeat="user in users | filter:filters">
<td>{{user.firstname}}</td>
<td>{{user.inactive}}</td>
</tr>
on click filter set to check box
<input type="checkbox" ng-click="filters.inactive = true">
First, You need to set controller name instade of "myCtrl.js" whatever your controller name.

displaying selected list of values from one list into another onclick in angularjs

i have list of data displayed in table. As i click any td i display the list of selected values in another table.The Problem is if i select more than one row then in addition to the previous record next selected value should also be displayed but as per my code that do not happen.Should i use checklist? Or changes can be done in the existing one.code is as follows:
<table class="table table-hover" style="width:300px;">
<tr ng-repeat="work in jointworkdata">
<td ng-click="selectedVal(tab,work.jointwork_name)">{{work.jointwork_name}}</td>
</tr>
and display table is:
<table class="table table-hover"><tr>
<td >{{selectedData}}</td></tr>
code in controller is:
$scope.selectedVal = function(tab,val) {
if(tab==1)
{
$scope.selectedData=val;}
};
The output gives one record at a time and not all selected since fucntion is getting called on click.
You can accomplish this with 2 way binding https://docs.angularjs.org/guide/databinding .
Lets say you have a simple Controller that has the primary data to display and then a variable that collected the ones the user is adding on.
app.controller = function($scope) {
$scope.data = [1,2,3,4];
$scope.data2 = new Array();
$scope.add = function(item) {
$scope.data2.push(item);
};
};
Now in the view its simple as displaying both of them
<tr ng-repeat="item in data">
<td ng-click="add(item)">{{ item }}</td>
</tr>
...
<tr ng-repeat="item2 in data2">
<td>{{ item2 }}</td>
</tr>
Two way binding will take care of automatically rerunning that ng-repeat if any new items are added to the data2 array.

Hide/show particular element on click with AngularJS

I have an HTML table with many rows in it and want to hide a row when the user clicks the delete button for that particular row. I'm having trouble doing it with Angular and the ng-hide directive.
Here's my (simplified) HTML code for just two rows:
<tr ng-hide="isRowHidden">
<td>Example template title</td>
<td>
Delete template
</td>
</tr>
<tr ng-hide="isRowHidden">
<td>Another example template title</td>
<td>
Delete template
</td>
</tr>
And here is my Angular code (in CoffeeScript) thus far:
$scope.deleteTemplate = (templateId) ->
console.log "Deleting template id #{templateId}"
$scope.isRowHidden = true
I know that the last line is incorrect because it hides all rows instead of just one. What am I missing? Thanks!
You need to model the data as an array with multiple isRowHidden values, then list the rows via ng-repeat:
http://jsfiddle.net/XqchD/ (uses JS, not coffee)
myApp = angular.module("myApp", [])
FieldCtrl = ($scope) ->
$scope.data = fields: [
value: "1F"
isRowHidden: false
,
value: "2F"
isRowHidden: false
]
$scope.deleteTemplate = (field) ->
console.log field
field.isRowHidden = true
HTML:
<table ng-repeat="field in data.fields">
<tr ng-hide="field.isRowHidden">
<td>{{field.value}}</td>
<td>
Delete template
</td>
</tr>
</table>

Resources