How to remove deleted row in ng-table - angularjs

I have a grid developed using ng-table and I need to remove selected item from grid table after removing from server-side. Already tried to call the grid loading ajax again, but it's not working.
My Controller,
app.controller('blockController', function($scope, $filter, $q, ngTableParams, $sce, Block) {
// Fetch data from server using RESTful API
$scope.load = function() {
// load serverside data using http resource service
Block.get({}, function (response) { // success
$scope.results = response.data;
var data = response.data; // store result to variable
// Start ng-table with pagination
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10 // count per page
}, {
total: data.length, // length of data
getData: function($defer, params) {
// use build-in angular filter
var orderedData = params.sorting() ? $filter('orderBy')(data, params.orderBy()) : data;
orderedData = params.filter() ? $filter('filter')(orderedData, params.filter()) : orderedData;
params.total(orderedData.length); // set total for recalc pagination
$defer.resolve($scope.blocks = orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
// un-check all check boxes
$scope.checkboxes = { 'checked': false, items: {} };
// watch for check all checkbox
$scope.$watch('checkboxes.checked', function(value) {
angular.forEach($scope.blocks, function(item) {
if (angular.isDefined(item.id)) {
$scope.checkboxes.items[item.id] = value;
}
});
});
// watch for data checkboxes
$scope.$watch('checkboxes.items', function(values) {
if (!$scope.blocks) {
return;
}
var checked = 0, unchecked = 0,
total = $scope.blocks.length;
angular.forEach($scope.blocks, function(item) {
checked += ($scope.checkboxes.items[item.id]) || 0;
unchecked += (!$scope.checkboxes.items[item.id]) || 0;
});
if ((unchecked == 0) || (checked == 0)) {
$scope.checkboxes.checked = (checked == total);
}
// grayed checkbox
angular.element(document.getElementById("select_all")).prop("indeterminate", (checked != 0 && unchecked != 0));
}, true);
}, function (error) { // error
$scope.results = [];
// error message display here
});
}
// Call REST API
$scope.load();
/*
|------------------------------
| Delete selected items
|------------------------------
*/
$scope.delete = function() {
var items = [];
// loop through all checkboxes
angular.forEach($scope.blocks, function(item, key) {
if($scope.checkboxes.items[item.id]) {
items.push(item.id); // push checked items to array
}
});
// if at least one item checked
if(items.length > 0) {
// confirm delete
bootbox.confirm("Are you sure to delete this data?", function(result) {
if(result==true) {
for (var i = 0; i < items.length; i++) {
// delete using $http resopurce
Block.delete({id: items[i]}, function (response) { // success
// remove the deleted item from grid here
// show message
}, function (error) { // error
// error message display here
});
}
}
});
}
}; // delete
}); // end controller
HTML Table,
<!-- data table grid -->
<table cellpadding="0" cellspacing="0" border="0" class="table table-striped table-bordered" ng-table="tableParams" show-filter="true">
<tbody>
<tr ng-repeat="block in $data">
<!-- serial number -->
<td data-title="'<?php echo $this->lang->line('sno'); ?>'" style="text-align:center" width="4">{{$index+1}}</td>
<!-- Checkbox -->
<td data-title="''" class="center" header="'ng-table/headers/checkbox.html'" width="4">
<input type="checkbox" ng-model="checkboxes.items[block.id]" />
</td>
<!-- Block Name -->
<td data-title="'<?php echo $this->lang->line('label_cluster_name'); ?>'" sortable="'block_name'" filter="{ 'block_name': 'text' }">
<span ng-if="!block.$edit">{{block.block_name}}</span>
<div ng-if="block.$edit"><input class="form-control" type="text" ng-model="block.block_name" /></div>
</td>
<!-- Description -->
<td data-title="'<?php echo $this->lang->line('label_description'); ?>'" sortable="'description'" >
<span ng-if="!block.$edit">{{block.description}}</span>
<div ng-if="block.$edit"><textarea class="form-control" ng-model="block.description"></textarea></div>
</td>
<!-- Edit / Save button -->
<td data-title="'<?php echo $this->lang->line('label_actions'); ?>'" width="6" style="text-align:center">
<a ng-if="!block.$edit" href="" class="btn btn-inverse btn-sm" ng-click="block.$edit = true"><?php echo $this->lang->line('label_edit'); ?></a>
<a ng-if="block.$edit" href="" class="btn btn-green btn-sm" ng-click="block.$edit = false;update(block)"><?php echo $this->lang->line('label_save'); ?></a>
</td>
</tr>
</tbody>
</table> <!-- table grid -->

You should remove the deleted item from the data collection once the server confirms the deletion.
You can do this manually from within the delete success callback instead of just reloading the complete collection (which is theoretically valid as well but will often be slower).
Then after removing the item from the collection, call the tableParams.reload() method to reload the table so the change is reflected in the table.
You can find a working example of the reload() method right here: http://plnkr.co/edit/QXbrbz?p=info
Hope that helps!

This is working for me:
$scope.deleteEntity = function (entity) {
bootbox.confirm("Are you sure you want to delete this entity ?", function (confirmation) {
if (confirmation) {
$http.delete("/url/" + entity._id)
.success(function (data) {
if (data.status == 1) {
var index = _.indexOf($scope.data, entity);
$scope.data.splice(index, 1);
$scope.tableParams.reload();
} else {
}
});
}
}
);
};

In version 1x of ng-table the following code works. In this example I'm using the MyController as vm approach and user is a $resource class object:
this.removeUser = function (user,i) {
user.$remove().then(function () {
this.tableParams.data.splice(i, 1);
}, function () {
// handle failure
});
});
When called in your HTML table, be sure to pass in $index as the second parameter, eg:
<button class="btn btn-danger btn-xs" ng-click="vm.removeUser(user, $index)" title="Delete User">
<i class="glyphicon glyphicon-trash"></i>
</button>
No need to call tableParams.reload or reload data from the server.

Related

AngularJS ng-click not responding when clicked

I know there is alot of questions about this topic out there, but could not find any solution to my problem. My code:
UPDATE
$scope.openOne = function (id) {
ImageService.getDetails(id).then(function (data) {
$scope.imageDetail = data;
}).catch(function (e) {
var message = [];
});
}
function getAllImages() {
ImageService.getImages().then(function (value) {
$scope.images = value;
var items = [];
$(value).each(function () {
var url = "https://someUrl/" + this.Image[0];
console.log(url);
items.push(`
<tr>
<td><button id="button" ng-click="openOne(${this._id})">${this.ImageName}</button></td>
<td>${this.ImageCategory}</td>
<td>
<img style="width:30%;" ng-src="${url}" alt="The Image is missing">
</td>
</tr>
`);
});
$("#body").append(items.join(''));
}).catch(function (e) {
var message = [];
}).finally(function (e) {
});
}
I am creating the button in in the controller and then appending it to the DOM.
Does anybody see the error? When I click the button nothing happens.
Approach is all wrong.
The fundamental principal in angular is let your data model drive the view and let angular compile that view from templates
A more typical set up would pass your images array to ng-repeat in the view:
Controller:
function getAllImages() {
ImageService.getImages().then(function (value) {
$scope.images = value;
});
}
View:
<tr ng-repeat="img in images track by $index">
<td><button id="button" ng-click="openOne(img.id)">{{img.ImageName}}</button></td>
<td>{{img.ImageCategory}}</td>
<td>
<img style="width:30%;" ng-src="{{img.url}}" alt="The Image is missing">
</td>
</tr>
You need to add $compile service here, that will bind the angular directives like ng-click to your controller scope. For example
app.controller('yourController', function($scope,$compile) {
var button = '<button id="button" ng-click="openOne(${this._id})">${this.ImageName}</button>';
items.push(button);
$("#body").append(items.join(''));
var temp = $compile(button)($scope);
$scope.openOne = function(){
alert('Yes Click working at dynamically added element');
}
});

Ng-Table is not binding from NgTableParams with server side data

Unable to bind the table with data i.e. collected from service.
Controller code is as:
app.controller('outletTypeController', ['$scope', '$location', '$timeout', 'outletTypesService', '$uibModal', 'NgTableParams', '$q', '$log',
function ($scope, $location, $timeout, outletTypesService, $uibModal, NgTableParams, $q, $log) {
$scope.message = "";
$scope.animationsEnabled = true;
$scope.outletTypes = [];
//To Load Outlet Types in same controller
$scope.LoadOutletTypes = function () {
outletTypesService.getOutletTypes().then(function (results) {
$scope.outletTypes = results.data.Result;
}, function (error) {
var errors = [];
if (response.data != null) {
for (var key in response.data.modelState) {
for (var i = 0; i < response.data.modelState[key].length; i++) {
errors.push(response.data.modelState[key][i]);
}
}
}
$scope.message = "Failed to load data due to:" + errors.join(' ');
});
};
//To Bind OutletType With Options in same controller
$scope.outletTypeWithOptions = function () {
//to set outletTypes
$scope.LoadOutletTypes();
var initialParams = {
count: 2 // initial page size
};
var initialSettings = {
// page size buttons (right set of buttons in demo)
counts: [10, 50, 100],
// determines the pager buttons (left set of buttons in demo)
paginationMaxBlocks: 5,
paginationMinBlocks: 1,
dataset: $scope.outletTypes
};
return new NgTableParams(initialParams, initialSettings);
};
and HTML View Code is as:
<div id="body" ng-controller="outletTypeController">
<table ng-table="outletTypeWithOptions" class="table table-striped" show-filter="true" cellspacing="0" width="100%">
<tr data-ng-repeat="type in $data">
<td title="'Logo'" class="text-center">
<div class="logoImg">
<img src="images/halalpalc.png" width="30" />
</div>
</td>
<td title="'Outlet Type'" filter="{ OTypeName: 'text'}" sortable="'OTypeName'">
{{ type.OTypeName }}
</td>
<td title="'Icon Rated'">I R</td>
<td title="'Icon Unrated'">I U</td>
<td title="'Status'" class="text-center status">
{{ type.IsActive}}
</td>
<td title="'Action'" class="text-center">
<!--<a href="#" class="editAction" data-toggle="modal" data-target="#myModal" title="Edit">
<img src="images/SVG_icons/edit_action.svg" />
</a>-->
<button data-ng-click="open()" class="btn btn-warning">Edit</button>
<!--<img src="images/SVG_icons/close_action.svg" />-->
</td>
</tr>
</table>
</div>
But unable to bind the data, However I try to bind it with Static Data it's properly working.
Here $scope.LoadOutletTypes is an async method call, which will asynchronously populate $scope.outletTypes with results. Rest of the code after LoadOutletTypes method call won't wait for result instead proceeds for execution, which will populate dataset in initialSettings object with null value(If it was unable to load the outlet types in time. But this will work for static data).
Try the below code..
$scope.LoadOutletTypes = function () {
outletTypesService.getOutletTypes().then(function (results) {
$scope.outletTypes = results.data.Result;
$scope.setOutletTypeWithOptions();
}, function (error) {
var errors = [];
if (response.data != null) {
for (var key in response.data.modelState) {
for (var i = 0; i < response.data.modelState[key].length; i++) {
errors.push(response.data.modelState[key][i]);
}
}
}
$scope.message = "Failed to load data due to:" + errors.join(' ');
});
};
$scope.setOutletTypeWithOptions = function () {
var initialParams = {
count: 2 // initial page size
};
var initialSettings = {
// page size buttons (right set of buttons in demo)
counts: [10, 50, 100],
// determines the pager buttons (left set of buttons in demo)
paginationMaxBlocks: 5,
paginationMinBlocks: 1,
dataset: $scope.outletTypes
};
$scope.NgTableParams = new NgTableParams(initialParams, initialSettings);
};
<div id="body" ng-controller="outletTypeController">
<table ng-table="NgTableParams" ng-init="LoadOutletTypes()" class="table table-striped" show-filter="true" cellspacing="0" width="100%">
<tr data-ng-repeat="type in $data">....

How to filter in ngTable

With Angular, I'm doing http request to take data. I've added ngTable and using it to display data. They correctly display in the table but I can't filters, sorting and delete them. Why?
js:
$scope.cancel = cancel;
function cancel(row, rowForm) {
var originalRow = resetRow(row, rowForm);
angular.extend(row, originalRow);
}
$scope.tableParams.reload().then(function(data) {
if (data.length === 0 && $scope.tableParams.total() > 0) {
$scope.tableParams.page($scope.tableParams.page() - 1);
$scope.tableParams.reload();
}
});
$http.get('my_url')
.success(function(data, status) {
$scope.data = data;
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10 // count per page
}, {
total: $scope.data.length, // length of data
getData: function($defer, params) {
// use build-in angular filter
var orderedData = params.sorting() ?
$filter('orderBy')($scope.data, params.orderBy()) :
$scope.data;
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
});
html:
<table ng-table="tableParams" show-filter="true" class="table table-bordered table-striped">
<tr ng-repeat="row in data track by row.id">
<td title="'Id'" filter="{id: 'text'}" sortable="'id'">{{row.id}}</td>
<td title="'Company'" filter="{company: 'text'}" sortable="'company'">{{row.company}}</td>
<td title="'Email'" filter="{email: 'text'}" sortable="'email'">{{row.email}}</td>
<td title="'Note'" filter="{note: 'text'}" sortable="'note'">{{row.note}}</td>
<td>
<button class="btn btn-default btn-sm" ng-click="cancel(row, rowForm)"><span class="glyphicon glyphicon-remove"></span></button>
</td>
</tr>
</table>
You are not applying any filters inside getData method.
First, you need to filter the data, then you sort:
getData: function($defer, params) {
// I will use a copy of the data to always start with the original data
// array ($scope.data). If you are getting the data with $resource or $http
// you can replace the $scope.data with the data obtained (eg.: response.data)
var theData = angular.copy($scope.data);
// First we filter using the filter object provided by the
// method 'filter()' of ngTableParams instance.
var filterObj = params.filter(),
filteredData = $filter('filter')($scope.data, filterObj);
// Then we sort the FILTERED DATA ARRAY
// NOTICE that the first parameter provided to $filter('orderBy')
// is the filtered array <filteredData> and not the original
// data array.
var sortObj = params.sorting(),
orderedData = $filter('orderBy')(filteredData, sortObj);
// Then we return the final data array (orderedData)
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}

MEAN Stack: Count and show the Sum of Values via AngularJS

Hi I'm a beginner with the MEAN Stack and currently stuck with a logical challenge.
I know how to get the count of elements of my table with {{element.length}} in HTML but I need to get the total sum of a given value.
Thanks for your help in advance!
HTML:
<div class="jumbotron text-center">
<h1>Volume <span class="label label-info">{{getTotal()}} </span></h1>
</div>
<div class="text-center" >
<table class="table" >
<thead>
<tr>
<th>Drink</th>
<th>Volume</th>
<th>Date</th>
<th>Comment</th>
<th>Action</th>
</tr>
</thead>
<tbody ng-repeat="drink in drinks">
<tr>
<td>{{drink.text}}</td>
<td>{{drink.volume}} Liter</td>
<td>{{drink.time}}</td>
<td>{{drink.comment}}</td>
<td><button type="submit" class="btn btn-primary btn-sm"
ng-click="deleteDrink(drink._id)">delete</button></td>
</tr>
</tbody>
</table>
</div>'
Model:
var mongoose = require('mongoose');
var Schema =new mongoose.Schema({
text : {type : String, default: ''},
volume: {type: Number, default: null},
zeit: {type: Date, default:Date.now},
comment: {type: String}
});
module.exports = mongoose.model('mongoose', Schema);'
Controller:
angular.module('drinkController', [])
// inject the drink service factory into our controller
.controller('mainController', ['$scope','$http','Drinks', function($scope, $http, Drinks) {
$scope.formData = {};
$scope.loading = true;
// GET =====================================================================
// when landing on the page, get all drinks and show them
// use the service to get all the drinks
Drinks.get()
.success(function(data) {
$scope.drinks = data;
$scope.loading = false;
});
// CREATE ==================================================================
// when submitting the add form, send the text to the node API
$scope.createDrink = function() {
// validate the formData to make sure that something is there
// if form is empty, nothing will happen
if ($scope.formData.text != undefined) {
$scope.loading = true;
// call the create function from our service (returns a promise object)
Drinks.create($scope.formData)
// if successful creation, call our get function to get all the new drinks
.success(function(data) {
$scope.loading = false;
$scope.formData = {}; // clear the form so our user is ready to enter another
$scope.drinks = data; // assign our new list of drinks
});
}
}
//Problem Function!! I don't know how to read desired values
$scope.getTotal=function(){
var total=0;
for (var i=0; i <$scope.drinks; i++){
var sum= $scope.drinks.volume[i]; //??
total= sum ; //?
}
return total;
}
// DELETE ==================================================================
// delete a todo after checking it
$scope.deleteDrink = function(id) {
$scope.loading = true;
Drinks.delete(id)
// if successful creation, call our get function to get all the new todos
.success(function(data) {
$scope.loading = false;
$scope.drinks = data; // assign our new list of todos
});
};
}]);
So I have at /api/drinks
[{"_id":"555c23943e0bf3fc403864c3",
"comment":"Yummie",
"__v":0,
"time":"2015-05-20T06:03:17.340Z",
"**volume":2**,
"text":"Coke"},
{"_id":"555c239d3e0bf3fc403864c4",
"comment":"Mooh!",
"__v":0,
"time":"2015-05-20T06:03:17.340Z",
**"volume"**:1,
"text":"Milk"}
]
In my HTML I need a Display of the Value of all Volume Entries, so it would be 3.
This should work:
$scope.getTotal=function(){
var total=0;
for (var i=0; i <$scope.drinks.length; i++){
total += $scope.drinks[i].volume;
}
return total;
}

updating model and binding update operations with UI

I currently have developed a table of content using AngularJS, the table will populate based on an Angular Service "Model" which invokes a web service and returns list and using ng-repeat and creating a table and all its content.
Everything at the moment works fine, I have a minor problem though. Part of the table, we are outputting an action button which when clicked invokes a web service which update the current record. Am trying to make the record data gets updated automatically, but i must refresh the page in order to see the changes.
Here is my code
My app.js
angular.module('my_vehicles', ['vehicleServices', 'AccountsDirectives']);
service.js
'use strict';
angular.module('vehicleServices', ['ngResource']).
factory('Car', function($resource) {
return $resource('/vehicle/api/car.json/:id', {},
{
query: {method:'GET', isArray:false},
delete: {method:'DELETE', isArray:false},
update: {method:'PUT', isArray:false}
}
);
});
controller.js
'use strict';
function MyVehicleController($scope, Car) {
var init = function() {
$scope.page_has_next = true;
$scope.cars = [];
$scope.page = 1;
};
// initialize values
init();
Car.query({my_vehicle: true},
// success
function(data) {
$scope.page_has_next = data.has_next;
$scope.cars = data.objects;
},
// error
function(data) {
}
);
$scope.mark_sold = function(id, index) {
Car.update({
id : id,
status : 'S'
},
function(data) {
});
}
$scope.delete = function(id, index) {
Car.delete(
{id: id},
// on success
function() {
// remove the element from cars array and it will be
// automatically updated by ng-repeat
$scope.cars.splice(index, 1);
$scope.loadMore(1);
}
);
}
$scope.is_total_zero = function() {
return !!($scope.cars.length)
//return $scope.cars.length > 0 ? true : false
}
$scope.loadMore = function(limit) {
if($scope.page_has_next) {
$scope.$broadcast('loading_started');
console.log(limit);
Car.query({my_vehicle: true, page: $scope.page, limit: limit},
// success
function(data) {
$scope.page_has_next = data.has_next;
$scope.cars = $scope.cars.concat(angular.fromJson(data.objects));
$scope.page++;
$scope.$broadcast('loading_ended');
},
// error
function() {
$scope.page_has_next = false;
$scope.$broadcast('loading_ended');
}
);
}
}
$scope.$on('loading_started', function() {
$scope.state = 'loading';
});
$scope.$on('loading_ended', function() {
$scope.state = 'ready';
});
}
and finally, my html code
<tr ng-repeat="car in cars">
<td>{% ng car._get_model_display.make_display %} {% ng car._get_model_display.model_display %} {% ng car._get_model_display.trim_display %}</td>
<td>{% ng car.created_at_format %}</td>
<td>{% ng car.view_count %}</td>
<td ng-model="car.status_label">{% ng car.status_label %}</td>
<td>
<div class="btn-group">
<button ng-disabled="car.status == 'S' || car.status == 'P'" ng-model="edit" class="btn btn-mini edit-btn">{% trans 'Edit' %}</button>
<button ng-disabled="car.status == 'S'" ng-click="delete(car.id, $index)" class="btn btn-mini delete-btn">{% trans 'Delete' %}</button>
<button ng-disabled="car.status == 'S' || car.status == 'P'" ng-click="mark_sold(car.id, $index)" class="btn btn-mini edit-btn">{% trans 'Mark as sold' %}</button>
</div>
</td>
</tr>
P.S the {% ng XXX %} is outputting {{ XXX }}, am using the above syntax because django templating engine does not allow me to use {{}} so i've developed a templatetag that would output {{}} ..
As mentioned earlier, my problem is that every time I invoke "mark as sold" it would invoke the cars.update() but it will not update the record displayed, must refresh to see changes. Any idea how i can solve this?
As far as I understand your code you only update the db without updating the cars model ($scope.cars) so changes are only reflected in the db but not in the AngularJS application.
Maybe try the following:
$scope.mark_sold = function(id, index) {
Car.update({
id : id,
status : 'S'
},
function(data) {
$scope.cars[id].status = 'S';
});
}
You need to also update your in-memory cars array.
You already have the array index (second parameter of the mark_sold function):
$scope.mark_sold = function(id, index) {
Car.update({
id : id,
status : 'S'
},
function(data) {
// Update in-memory array
$scope.$apply(function(scope) {
scope.cars[index].status = 'S';
});
});
}

Resources