Refreshing ng-repeat without $scope, without new request to sever - angularjs

I have a table with this content:
<tbody>
<tr ng-repeat="result in ctrl.result track by $index">
<td ng-bind="$index+1"></td>
<td ng-bind="::result.title"></td>
<td> <button type="button" class="btn" ng-click='ctrl.deleteItem(result)'>Delete</button></td>
</tr>
</tbody>
And in my controller I have:
vm.deleteItem = function (result) {
myService.deleteItem(result.id)
.then(function (response) {
vm.result.splice(result, 1);
});
};
As you see, the vm.result has changed if the item be deleted successfully.
Now, the item deleted in db, so we have response and then the item has been removed from vm.result, too. But the list hasn't updated in browser.
As you see, I use controller as approach and not $scope .

Try deleting the item this way:
vm.result.splice(vm.result.indexOf(result), 1);
The first Splice parameter should be the index of element rather than element itself.

var index = vm.result.findIndex(function(item) {
if (item.id == test.id) {
return true;
}
});
if (index !== -1) {
// Removing the test from list;
vm.result.splice(index, 1);
}
check based on id from the array test.id is the id of the element u r deleting

Related

Prevent users from selecting same value in multiple dropdowns

I am loading a table from an API call , table rows are dynamic and it is based on the returned values from API call. I am displaying sort order and value should be unique and user shouldn't select a previously selected values. I tried to follow as per this (http://jsfiddle.net/jnash21/oqezom4y/) but i am not able to achieve as mine is dynamic.
I tried this (http://embed.plnkr.co/QU4r05n9rQprwyL9Ltxh/) .
editor.controller('EditorController', function($scope) {
$scope.entities = [{name:"pencil",sortOrder:""} ,{name:"notepad",sortOrder:""} ,
{name:"bookshelf",sortOrder:""}
];
$scope.sortOrderValues=[1,2,3];
});
<table>
<tr ng-repeat="x in entities">
<td>{{ x.name }}</td>
<td><select ng-model="x.sortOrder"
ng-options="col for col in sortOrderValues">
</select>
<span ng-show="!x.sortOrder"> * sort order required</span>
</td>
</tr>
</table>
How can I prevent a user from selecting same sort order in each row using angular js?
This plunker might help you.
First of all, genereate an array from 1 to entities.length (this case, 3).
When you select an option, tirgger the optionSelected function. This function will generate your inital array and calculate the used sortOrders by your entities. Then it filters the second ones from the first array.
HTML
<div ng-controller="EditorController">
<table>
<tr ng-repeat="x in entities">
<td>{{ x.name }}</td>
<td><select ng-model="x.sortOrder"
ng-options="col for col in sortOrderValues"
ng-change="optionSelected()">
</select>
<span ng-show="!x.sortOrder"> * sort order required</span>
</td>
</tr>
</table>
</div>
CONTROLLER
editor.controller('EditorController', function($scope) {
$scope.entities = [{name:"pencil",sortOrder:""} ,{name:"notepad",sortOrder:""} ,
{name:"bookshelf",sortOrder:""}
];
// Genereate all the numbers between 1 and $scope.entities.length
$scope.sortOrderValues= $scope.entities.map(
function (item, index) {
return index + 1;
}
);
// Function executed when you select a sortOrder
$scope.optionSelected = function () {
// Genereate all the numbers between 1 and $scope.entities.length
var allIndexes = $scope.entities
.map(function (entity, index) { return index + 1; });
// Get all the sortOrder used
var usedIndexes = $scope.entities
.map(function(e) { return e.sortOrder; });
// Remove from the [1, .., $scope.entities.length] array all the sortOrder used
$scope.sortOrderValues = allIndexes
.filter(function (order) {
return !usedIndexes.find(function(index) { return index === order; });
});
}
});

How to pass a value into a react button

I have the following method as part of one of my components in a react app.
renderDeducs()
{
var deducArray=[];
for(var x =0;x<this.props.deducciones.length;x++)
{
var deduc = this.props.deducciones[x];
deducArray.push(<tr key={x}>
<td key={x.toString()+"nombre"}>{deduc.nombre}</td>
<td key={x.toString()+"porciento"}>{deduc.porciento}</td>
<td><button onClick={(e) => {this.delete(deduc.nombre)}}>Borrar</button> | <button>Editar</button> </td>
</tr>
);
}
console.log(deducArray);
return deducArray;
}
The idea is to be able to display the items of an array and provide a delete button for each item. The items are displayed inside an HTML table. However, the button for each row is deleting the last item in the array (the last row of the table). Apparently, even though "deduc" is a local variable and should be out of scope when the click events fire, deduc seems to have the value used in the last iteration of the loop. How can I tell each button what item of the array I want to delete?
EDIT:
here is the code for the "delete" method of the component and the constructor:
constructor(props)
{
super(props);
this.state = {
addMethod : this.props.addMethod,
delMethod : this.props.delMethod
};
this.renderDeducs = this.renderDeducs.bind(this);
this.delete = this.delete.bind(this);
}
delete(nombre)
{
alert("Deleting " + nombre);
this.state.delMethod(nombre);
}
As you can see, the actual delete from the array method happens on a method that is bound to a component higher up in the component tree (that how you you achieve the "single source of truth", isn't it?) On the parent component, this is what that method looks like:
delDeduction(nombre)
{
var stateArray = this.state.deducciones;
for (var x =0;x<stateArray.length;x++)
{
if(stateArray[x].nombre === nombre)
{
stateArray.splice(x,1);
this.setState({deducciones:stateArray});
return;
}
}
}
Change code as:
Your problem is, deduc is defined as var, so deduc is hoisted inside the function. Then try to define it with let, it will prevent this behaviour.
renderDeducs()
{
var deducArray=[];
for(var x =0;x<this.props.deducciones.length;x++)
{
let deduc = this.props.deducciones[x];
deducArray.push(<tr key={x}>
<td key={x.toString()+"nombre"}>{deduc.nombre}</td>
<td key={x.toString()+"porciento"}>{deduc.porciento}</td>
<td><button onClick={(e) => {this.delete(deduc.nombre)}}>Borrar</button> | <button>Editar</button> </td>
</tr>
);
}
console.log(deducArray);
return deducArray;
}
Info about javascript hoisting
You forgot to bind the handler.Also make sure to use the loop like below , it will make your life easy
renderDeducs() {
return (
{
this.props.deducciones.map(deduc =>
<tr>
<td key={x.toString()+"nombre"}>{deduc.nombre}</td>
<td key={x.toString()+"porciento"}>{deduc.porciento}</td>
<td>
<button onClick={this.deleteme.bind(this, deduc.nombre)}>
Borrar
</button> |
<button>Editar</button>
</td>
</tr>
)
}
);
}
deleteme(n){
let initial_val = this.props.deducciones.slice();
let obj_to_del= initial_val.find(d => d.nombre === n);
initial_val.remove(obj_to_del);
//update your state with the initial val
}

Checkbox checked not updating on delete, its updating the second time

i have a code like this:
<body ng-app="UserManagement" ng-controller="UserManagementController">
<h3>to do</h3>
<form ng-submit="addtodo();">
<table>
<tr><td colspan="2"><input type="checkbox" ng-model="employees.todo" /></td></tr>
<tr><td colspan="2">{{remng()}} of {{actuallength}} remaining</td></tr>
<tr ng-repeat="emp in employees">
<td><input type="checkbox" ng-model="emp.todo" /></td>
<td>{{emp.name}}</td>
</tr>
<tr>
<td><input type="text" ng-model="addemp" /></td>
<td><input type="button" value="Add" ng-click="addemps()"/></td>
</tr>
<tr>
<td><input type="button" value="Delete" ng-click="deleteemps();"/></td>
</tr>
</table>
</form>
</body>
here i am making simple add, delete operation of a list of employees. In the delete operation, when i click delete without checking any checkbox, the items with existing checked checkboxes are deleted, but when i click any checkbox and press delete, the clicked checkbox is not deleted this time, but when i click delete second time, it deletes.
Js code:
var app = angular.module("UserManagement", []);
//Controller Part
app.controller("UserManagementController", function($scope, $http) {
$scope.employees = [
{name:'Abhinav',todo:true},
{name:'Amit', todo:false},
{name:'Raghav',todo:true},
{name:'Sumit', todo:false},
{name:'Ashwani',todo:true},
{name:'Mihir', todo:false},
]
$scope.totalsel = $scope.employees.length;
$scope.actuallength = $scope.totalsel;
alert($scope.actuallength);
//$scope.addtodo = function(){}
//alert("ddd");
$scope.deleteemps = function(){
//alert($scope.employees.name);
$scope.deleted_emps = [];
//alert("in foreach: "+$scope.employees[2].todo);
angular.forEach($scope.employees, function(todos, index) {
//alert(todos.todo);
//alert(todos.name);
if(todos.todo){
// alert(index)
var deletednames = todos.name;
// var deletedtodo = todos.todo;
//$scope.deleted_emps.push(deletednames)
// alert(deletednames);
$scope.deleted_emps.push({name:todos.name, todo:todos.todo});
//var abc=angular.toJson($scope.deleted_emps);
// alert(index);
//console.log(angular.toJson(todos.name));
console.log("hiii: "+$scope.deleted_emps.name);
var indx;
for (var i=0; i<$scope.deleted_emps.length; i++) {
console.log("iii: "+$scope.deleted_emps[i].name);
console.log("i: "+$scope.employees[index].name);
//console.log($scope.employees[index].name.indexOf($scope.deleted_emps[i].name));
indx = $scope.employees[index].name.indexOf($scope.deleted_emps[i].name);
// alert(indx);
if (indx > -1) {
// alert(indx);
//$scope.employees.splice()
$scope.employees.splice(index, 1);
}
}
/* var indx;
for (var i=0; i<array2.$scope.deleted_emp; i++) {
indx = array1.indexOf(array2[i]);
if (indx > -1) {
array1.splice(indx, 1);
}
}
*/
}
$scope.actuallength = $scope.totalsel;
})
}
});
I am using angular js 1.6.1 . Thanks in advance.
I've made a fiddle based on your codes.
Add and Delete Employees
Sample code of mine is like this.
$scope.deleteEmp = function(){
var slicedEmps = [];
angular.forEach($scope.employees, function(e){
if(!e.isChecked){
slicedEmps.push(e);
}
});
$scope.employees = slicedEmps;
};
What I suggested is making new array instead of using 'splice'.
I hope this fiddle can help you. :)

How to use ng-click value as ng-repeat property?

How to get $scope.clickedVal in r.clickedVal?
Button click calls a function, passing in two parameters:
<a ng-click="display('Info', 'Admission_Info'); filters.Admission_Info= '!!'; ">Info</a>
<a ng-click="display('Info', 'SomeOther_Info'); filters.SomeOther_Info= '!!'; ">Other</a>
Function in the controller:
$scope.display = function (col, val) {
$scope.filters = {};
$scope.clickedColumn = col;
$scope.clickedVal = val;
};
Table displays a filtered view with 2 columns.
<tr ng-repeat="r in response | filter:filters as filtered " ng-show="filtered.length">
<td>{{ r.Name }}</td>
<td>{{ r.clickedVal }}</td>
</tr>
{{ r.{{clickedVal}} }} didn't work.
So for example, if the first button is clicked, r.clickedVal should return r.SomeOther_Info.
I've tried creating a filter as well but run into the same issue - m.value is incorrect.
SchoolProgramsApp.filter('myFilter', function () {
return function (input, column, value) {
var out = [];
angular.forEach(input, function (m) {
if (m.value === value) {
out.push(m)
}
})
return out;
}
});
You should use bracket notation to access property of the object by variable name:
{{ r[clickedVal] }}

Mutliplr print functionality return inconsistent data , on changing $timeout value

I want to print a multiple barcode slip, each will have different barcode.
Using a print service to print the div content,
(function() {
'use strict';
angular.module('app.services')
.factory('PrintService', PrintService);
PrintService.$inject = [];
function PrintService() {
var service = {
printElement: printElement
};
return service;
function printElement(elem) {
var printSection = document.getElementById('printSection');
// if there is no printing section, create one
if (!printSection) {
printSection = document.createElement('div');
printSection.id = 'printSection';
document.body.appendChild(printSection);
}
var elemToPrint = document.getElementById(elem);
// clones the element you want to print
var domClone = elemToPrint.cloneNode(true);
printSection.innerHTML = '';
printSection.appendChild(domClone);
window.print();
window.onafterprint = function() {
printSection.innerHTML = '';
}
};
}
})();
Using this print service, will print the slip. Slip data will bind.
var userServicePromise = UserService.printBarCodes(sampleId);
userServicePromise.then(function(response) {
if (response != null && response.data != null && response.data.result != null) {
response.data.result.forEach(function(entry) {
/* $timeout(function() {
vm.barCodeImage = angular.copy(entry);
}, 0);*/
//vm.testName = item.testMast.testName.slice(0, 3);
vm.barCodeImage = angular.copy(entry);
$timeout(function() {
PrintService.printElement("printThisElement");
}, 1);
});
} else {
toaster.error(response.data.message);
}
});
This is the html which will be printed eventually, using DOM element id for printing.
<div id="printThisElement" class="onlyprint" >
<table>
<tr>
<td>{{ ctrl.instCode }}</td>
<td align="center">{{ ctrl.date | dateDisplayFilter}} </td>
</tr>
<tr>
<td colspan="2" align="center"> <img ng-src="data:image/JPEG;base64,{{ctrl.barCodeImage}}"> </td>
</tr>
<tr>
<td colspan="2" align="center">{{ ctrl.user.name }} </td>
</tr>
<tr>
<td >Reg Id: {{ ctrl.regIdLookup }}</td>
<td align="center">{{ ctrl.testName }}</td>
</tr>
</table>
</div>
Expected out put is three slips with different barcode:
7865
7866
7867
Output is three slips with same barcode
7865
7865
7865
some times,
7866
7866
7866
On changing the $timeout(function() value output be like
7865
7865
7866
what can be the reason for this ?
Never ever modify the DOM from inside a service, that's just totally against the whole way Angular works. What you should do instead is create a model of the data (and it's quite alright to create that in the service) and use Angular's templates to render that model in the page.
The reason your code doesn't work is that you are trying to re-use vm.barCodeImage for different images on the page. Angular tracks the changes and will redraw existing parts of the page. That is why you get the same barcode repeated: the different copies each use the same model so they will be the same.
A simple solution is to create an array ofvm.barCodeImages and then just render them in an ng-repeat loop. A better way might be to create a myBarcode directive which uses UserService.printBarCodes to create one barcode in an isolated scope and then your template will look shorter and tidier.

Resources