AngularJS: How to freeze orderBy in ng-repeat during edit mode - javascript

I'm using md-data-table and I have add sorting options based on column.
Below, presented my html(pug format) code:
table(md-table md-row-select multiple='' ng-model='vm.selected' md-progress='promise')
//- columns
thead(md-head class='back-color')
tr(md-row)
th(md-column ng-click='vm.orderingBy(name)')
span Name
th(md-column ng-click='vm.sortingBy(code)')
span Code
//- rows
tbody(md-body)
tr(md-select='record' md-select-id='id' ng-repeat='record in vm.records | orderBy:vm.orderByColumn)
//- name
td(md-cell)
p(ng-hide='vm.columns.edit') {{record.name}}
md-input-container(ng-if='vm.columns.edit' class='no-errors-spacer md-no-margin')
input(ng-model='record.name' md-select-on-focus)
//- code
td(md-cell)
p(ng-hide='vm.columns.edit') {{record.sorting_code}}
md-input-container(ng-if='vm.columns.edit' class='no-errors-spacer md-no-margin')
input(ng-model='record.code' md-select-on-focus)
My AngularJS(Javascript) code presented below:
vm.orderByColumn = 'name';
vm.orderingBy = function(ordering) {
vm.orderByColumn = ordering;
}
The problem is when the table is ordered by 'code' and I'm trying to edit the record's code, the order of records changing while you change the value of code. So, the result is very confused.
I'm thinking if there is any way to freeze the order while I'm in edit mode.

Outsource your orderBy logic into your controller and make it block in edit mode by using a simple switch variable like in this example fiddle. I hope this working example will help you to implement this logic inside your application.
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function ($scope, orderByFilter) {
$scope.edit = false;
$scope.data = [{
name: 'Frank'
},{
name: 'Peter'
},{
name: 'Basti'
},{
name: 'Sven'
},{
name: 'Franky'
},{
name: 'Sveny'
},{
name: 'bob'
}];
$scope.order = {
column: '',
revers: false
}
$scope.toggleEditMode = function () {
$scope.edit = !$scope.edit;
}
$scope.orderBy = function (column) {
if (!$scope.edit) {
$scope.order.column = column;
$scope.order.reverse = !$scope.order.reverse; //toggle revers
$scope.data = orderByFilter($scope.data, $scope.order.column, $scope.order.reverse);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<div>
<h3 ng-click="orderBy('name')">
Name
</h3>
<p ng-repeat="item in data">
<input type="text" ng-model="item.name" ng-if="edit" />
<span ng-if="!edit">{{ item.name }}</span>
</p>
</div>
<button ng-click="toggleEditMode()">
Toggle edit mode
</button>
</div>
</div>

I had this issue for a while and I've found a pretty simple solution. I made the sorting method by myself using $filter,
On my case : Instead of
<tr ng-repeat="schedule in schedules | orderBy:filerTable2:filterasc track by $index">
I just put
<tr ng-repeat="schedule in schedules">
And I used setFiler method to sort the list using filter parameter as the filter name.
$scope.setFiler = function(filter){
if($scope.filerTable2 == filter){
$scope.filterasc = !$scope.filterasc;
}
else{
$scope.filerTable2 = filter;
$scope.filterasc = false;
}
$scope.schedules = $filter('orderBy')($scope.schedules, filter, $scope.filterasc);
};

Related

ng-click function is not called with onclick in a AngularJS?

I have to call the ng-click function with the onClick but in my case ng-click function is not
//Controller function
$scope.editProductDetail = function(productObject) {
$scope.getProduct = productObject;
}
<a href="#"
onclick="document.getElementById('editProduct').style.display='block'" ng-click="editProductDetail(list)" target="_self">
</a>
call but model is open with onClick function?
It seems you're trying to set a class to the selected item from a product list, it seems you're confusing some AngularJS concepts.
If you're using AngularJS there's no need to use both onclick and ng-click.
If you want to show all products from your list you may want to use ng-repeat.
You need to initialize your Module for your AngularJS controller to load, and the controller must be within the module in the HTML code.
I've done an example bellow based on your code, it might help if you edit your answer and add your complete code.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.count = 0;
$scope.selectedIndex = 0;
$scope.editProductDetail = function (index) {
$scope.selectedIndex = index;
};
$scope.productList = [
{ name: 'Product 1', price: '1,00 U$' },
{ name: 'Product 2', price: '2,00 U$' },
{ name: 'Product 3', price: '3,00 U$' }
];
});
.selected-item {
display: block;
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl" >
<h2>Selected Item Number: {{ selectedIndex + 1}}</h2> <!-- I've added +1 since index starts at 0 -->
<div ng-repeat="item in productList">
{{ item.name}} {{item.price}}
</div>
</div>
As debabrata was saying you don't need to use both, just use something like this:
// Your controller
$scope.editProductDetail = function(productObject) {
$scope.setDisplayBlock = true;
$scope.getProduct = productObject;
}
// Your HTML
<span id="editProduct" ng-class="{'css-class-with-display-block': setDisplayBlock}">The element to change</span>

reflect change made by object affectation to scope

I try to cancel changes made to a ng-repeat item by re-affecting a copy of it that I made just before editing it, the original object is affected but nothing change in the view. It's just plain weird, and I haven't figure out why!
http://jsfiddle.net/leseulsteve/a16j16mk/8/
<div ng-controller="MyCtrl">
<ul ng-repeat="item in list">
<li ng-click="edit(item)">{{item.description}}</li>
</ul>
{{originalDescription}}
</div>
--
function MyCtrl($scope, $timeout) {
$scope.list = [{
description: 'I love bacon'
}, {
description: "J'aime le bacon"
}];
$scope.edit = function (item) {
var originalItem = angular.copy(item);
item.description = 'aaa'; /// update the view
$timeout(function () {
item = originalItem; // doesn't update the view :((
$scope.originalDescription = item.description; // Show the original description.
}, 1000);
}
}

Angular ng-class performance issue when too many elements in DOM

I have been working on a complex angular page which has been causing performance issue. To highlight the problem I have created a fiddle http://jsfiddle.net/4ex2xgL1/3/ here.
Essentially the performance issue is being caused by ng-class statement which has a function in it.
<span class="done-{{todo.done}}" ng-class="myfunction()">{{todo.text}}</span>
The span is in an ng-repeat. On running the fiddle one can see that ng-class gets executed several times when the page loads and on each key up it gets called as many time as number of items in the TODO list.
This is a lot simpler case, in my case I have 780 items on my page and the function ends up being evaluated aroung 3000 times!
One of the solution we saw is to break up the scope but it will cause almost a rewrite of my app.
We also tried https://github.com/Pasvaz/bindonce but it doesn't seem to be working with highly dynamic content.
Any thoughts?
I built a tree with https://github.com/JimLiu/angular-ui-tree with almost 500 items to render, with quite a lot of listeners. It takes 5 seconds to render. Bindonce won't work there.
The only solution out there is make ng-repeat do less. Keep the list small with a pagination, search or anything. Its the best shot as far as I know.
Well here are my recommendations
use ng-change on the checkbox to manipulate dom or anything rather using ng-class, it will improve your performance drastically.
<li ng-repeat="todo in todos track by todo.id">
<input type="checkbox" ng-model="todo.done" ng-change="myfunction()">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
http://jsfiddle.net/4ex2xgL1/3/
use track by in ng-repeat if you have ids, more here http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/
dont show 780 items in a list. Use a searchbox to show some 100 or 50 or you know better
quick-ng-repeat not used yet, try testing it https://github.com/allaud/quick-ng-repeat
finally a few good http://tech.small-improvements.com/2013/09/10/angularjs-performance-with-large-lists/
Finally I found the solution and it will helps lot to improve performance in angular js.
If your model changes dynamically and if you have lots of data and then also it improve AngularJS pages rendering up to 1000% and more - no kidding !.
Fore more information you can visit : http://orangevolt.blogspot.in/2013/08/superspeed-your-angularjs-apps.html
Follow the steps:
download the library from the link:library
2.example without library:(check your console)
function MyController( $scope) {
var entries = [
{ label : 'one', value : 'first entry'},
{ label : 'two', value : 'second entry'},
{ label : 'three', value : 'third entry'}
];
$scope.label ="";
$scope.value ="";
$scope.order = 'label';
$scope.add = function() {
entries.push({
label : $scope.label,
value : $scope.value
});
};
$scope.getEntries = function() {
console && console.log( "getEntries() called");
return entries;
};
}
<script src="https://raw.githubusercontent.com/lodash/lodash/2.4.1/dist/lodash.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<form name="myform" ng-app ng-controller="MyController">
Label/Value :
<input type="text" required ng-model="label">
<input type="text" required ng-model="value">
<button
ng-disabled="!myform.$valid"
ng-click="add()"
>Add</button>
<fieldset>
<legend>
Entries sorted by
<select
ng-model="order"
ng-options="property for property in [ 'label', 'value']">
</select>
</legend>
<div ng-repeat="entry in getEntries() | orderBy:order">
{{entry.label}} = "{{entry.value}}"
</div>
</fieldset>
</form>
3.example with library:(check your console)
function MyController( $scope) {
var entries = [
{ label : 'one', value : 'first entry'},
{ label : 'two', value : 'second entry'},
{ label : 'three', value : 'third entry'}
];
$scope.label ="";
$scope.value ="";
$scope.order = 'label';
$scope.add = function() {
entries.push({
label : $scope.label,
value : $scope.value
});
// clear cache
$scope.getEntries.cache = {};
};
$scope.getEntries = _.memoize(
function() {
console && console.log( "getEntries() sorted by '" + $scope.order + " 'called");
// return entries sorted by value of $scope.order
return _.sortBy( entries, $scope.order);
},
function() {
// return the cache key for the current result to store
return $scope.order;
}
);
}
<script src="https://raw.githubusercontent.com/lodash/lodash/2.4.1/dist/lodash.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<form name="myform" ng-app ng-controller="MyController">
Label/Value :
<input type="text" required ng-model="label">
<input type="text" required ng-model="value">
<button
ng-disabled="!myform.$valid"
ng-click="add()"
>Add</button>
<fieldset>
<legend>
Entries sorted by
<select
ng-model="order"
ng-options="property for property in [ 'label', 'value']">
</select>
</legend>
<div ng-repeat="entry in getEntries()">
{{entry.label}} = "{{entry.value}}"
</div>
</fieldset>
</form>

How to get selected checkboxes on button click in angularjs

I want to do something like this
<input type="checkbox" ng-model="first" ng-click="chkSelect()"/><label>First</label>
<input type="checkbox" ng-model="second" ng-click="chkSelect()"/><label>Second</label>
<input type="checkbox" ng-model="third" ng-click="chkSelect()"/><label>Third</label>
<input type="checkbox" ng-model="forth" ng-click="chkSelect()"/><label>Forth</label>
<button>Selected</button>
On button click I want to display selected checkbox labelname.
$scope.chkSelect = function (value) {
console.log(value);
};
Because the checkboxes are mapped, you can reference $scope.first, $scope.second, etc in your chkSelect() function. It's also possible to have a set of checkboxes mapped as a single array of data instead of having to give each checkbox a name. This is handy if you are generating the checkboxes, perhaps from a set of data.
I agree with Bublebee Mans solution. You've left out a lot of detail on why you're trying to get the label. In any case if you REALLY want to get it you can do this:
$scope.chkSelect = function (value) {
for(var key in $scope){
var inputs = document.querySelectorAll("input[ng-model='" + key + "']");
if(inputs.length){
var selectedInput = inputs[0];
var label = selectedInput.nextSibling;
console.log(label.innerHTML);
}
};
};
You can mess around with it to see if it's indeed selected.
fiddle: http://jsfiddle.net/pzz6s/
Side note, for anybody who knows angular please forgive me.
If you are dealing with server data, you might need isolated html block and deal with data in controller only.
You can do it by creating array in controller, maybe your data from response, and use ngRepeat directive to deal independently in html code.
Here is what I am telling you:
HTML:
<form ng-controller="MyCtrl">
<label ng-repeat="name in names" for="{{name}}">
{{name}}
<input type="checkbox"
ng-model="my[name]"
id="{{name}}"
name="favorite" />
</label>
<div>You chose <label ng-repeat="(key, value) in my">
<span ng-show="value == true">{{key}}<span>
</label>
</div>
</form>
Javascript
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.names = ['pizza', 'unicorns', 'robots'];
$scope.my = { };
}
You want to have something like the following in your controller (untested, working from memory):
$scope.checkBoxModels = [ { name: 'first', checked: false }, { name: 'second', checked: false }, { name: 'third', checked: false }, { name: 'fourth', checked: false } ];
Then in your view:
<input ng-repeat"checkboxModel in CheckBoxModels" ng-model="checkBoxModel.checked" ng-click="chkSelect(checkBoxModel)" /><label>{{checkBoxModel.name}}</label>
Then update your function:
$scope.chkSelect = function (checkBoxModel) {
console.log(checkBoxModel.name);
};

AngularJS Selection - setting ng-model in controller does not update selected value

I'm facing a problem in upgrading my ng-model in selection.
I have the following HTML:
<div ng-app>
<div ng-controller="Ctrl">
<select ng-model="viewmodel.inputDevice"
ng-options="i.label for i in viewmodel.inputDevices">
</select>
</div>
</div>
And the following code:
function Ctrl($scope) {
// view model
$scope.viewmodel = new function () {
var self = this;
var elem1 = {
value: '1',
label: 'input1'
};
var elem2 = {
value: '2',
label: 'input2'
}
self.inputDevices = [elem1, elem2];
self.inputDevice = {
value: '1',
label: 'input1'
};
};
}
You can use the following JSFiddle
What I want to do is put in inputDevice the same values that the first device has in the collection inputDevices.
I know that I can pass elem1 and it will work however i can't do it since i want to save the selection in Local Storage and than restore it to the ng-model object.
Any suggestion will be grateful
Thanks
You can either store the value instead of the object as Maxim has demonstrated, or you can pull the correct value from the inputDevices array with something like:
self.inputDevice = self.inputDevices.filter(function(item) {
return item.value == storedValue.value;
})[0];
as per an updated fiddle
The code in the original question works for me:
<div ng-app>
<div ng-controller="Ctrl">
<select ng-model="viewmodel.inputDevice"
ng-options="i.label for i in viewmodel.inputDevices">
</select>
<!-- displays the initial and any further selections
correctly as : {"value":"1","label":"input1"} -->
<span>{{viewmodel.inputDevice}}</span>
</div>
</div>
Your js code code works no doubt, but the viewmodel can be build a little easier:
function Ctrl($scope) {
// view model
$scope.viewmodel = {inputDevices: [
{value: '1', label: 'input1'},
{value: '2', label: 'input2'}
]};
$scope.viewmodel.inputDevice = $scope.viewmodel.inputDevices[0];
}
jsfiddle http://jsfiddle.net/8t2Ln/39/
Instead:
self.inputDevice = {
value: '1',
label: 'input1'
};
I would store index only:
self.inputDevice = 0; // or 1 - second item
and:
<select>
<option ng-repeat="i in viewmodel.inputDevices"
value="{{i.label}}"
ng-selected="viewmodel.inputDevices.indexOf(i) == viewmodel.inputDevice"
>{{i.label}}</option>
</select>
This way will work.
Fixed Demo Fiddle

Categories

Resources