I am having some difficulties understanding the properties/functions available through ui-grid. I often get confused with its previous version ng-grid. I am trying to find what the best way of deleting a checked-entry would be. Here is my markup, but due to not quite understanding if I have an index, or count available through a row entity:
HTML:
<div class="form-group">
<button type="button" id="addData" class="btn btn-success" ng-click="addData()">Add Data</button>
<button type="button" id="removeData" class="btn btn-success" ng-click="removeData()">Remove First Row</button>
<br>
<br>
<div id="grid1" ui-grid="gridOptions" ui-grid-edit ui-grid-selection external-scopes="myViewModel" class="grid"></div>
</div>
which lies under my controller:
$scope.removeData = function () {
console.log($scope.gridApi.selection.getSelectedRows());
var items = $scope.gridApi.selection.getSelectedRows();
angular.forEach($scope.myData, function (data, index) {
angular.forEach(items, function (item) {
if (item.displayValue = data.displayValue)
{
$scope.myData.splice(index, 1);
}
});
where displayValue is a property of my column and $scope.myData is my data. Is there a different way to send that selection to the controller for removal? The current way I have it does NOT work (obviously). Any help will be appreciated. If my markup is incomplete, I'll update it as necessary. Thank you!
Your solution looks a little complicated. Here is my delete function:
$scope.deleteSelected = function(){
angular.forEach($scope.gridApi.selection.getSelectedRows(), function (data, index) {
$scope.gridOptions.data.splice($scope.gridOptions.data.lastIndexOf(data), 1);
});
}
Here is a plunker based on the 210_selection tutorial.
ui-grid has problem with array.splice() method
This method is giving a problem which is making array replaced by the deleted row or item.
$scope.gridOptions.data.splice(index,1)
So the better way to handle delete of a row is by doing two things
Step 1:
$scope.gridApi.core.setRowInvisible(row)
The line above will hide the selected row
Step 2: Call the service which deletes the data at the database
I don't know how proper my solution is, but here is my code (maybe it can guide someone in the right direction or if they have a better method, please share :) )
$scope.removeData = function () {
angular.forEach($scope.gridOptions.data, function (data) {
angular.forEach($scope.gridApi.selection.getSelectedRows(), function (entity, index) {
if (entity.$$hashKey == data.$$hashKey) {
$scope.gridApi.selection.unSelectRow(entity);
//timeout needed to give time to the previous call to unselect the row,
//then delete it
$timeout(function () {
$scope.gridOptions.data.splice($scope.gridOptions.data.indexOf(entity), 1);
}, 0,1);
}
});
});
};
Hope it helps somebody!
I have a button that looks like this, which I specify in the cellTemplate value in my grid columnDefs...
columnDefs: [
// snipped other columns
{ name: '_delete', displayName: '', width: '5%', cellTemplate: '<div class="ui-grid-cell-contents ng-binding ng-scope"><button class="btn btn-danger btn-xs btn-block" ng-click="getExternalScopes().delete($event, row)"><span class="glyphicon glyphicon-trash"></span></button></div>', enableFiltering: false, disableColumnMenu: true }
My controller has a line which (IIRC) enables the getExternalScopes() call to work
$scope.$scope = $scope;
Then I handle the delete event I'm triggering like this in my controller...
$scope.delete = function (event, row) {
MyService.Delete({ action: row.entity.MyIdField }); // tells the server to delete the entity
$scope.gridApi.core.setRowInvisible(row); // hides that row in the UI
}
Perhaps this helps?
// $scope.gridApi.grid.cellNav.lastRowCol = null;
$scope.gridApi.grid.cellNav.focusedCells = [];
var cells = $(".ui-grid-cell");
// var focused = $(".ui-grid-cell-focus");
for (var i = 0; i < cells.length; i++) {
var div = $(cells[i].children[0]);
div.removeClass('ui-grid-cell-focus');
}
To answer #dileep's query extending on #Kevin Sage answer. This approach uses a service to send a delete request to the server and only delete the row once a successful response has been received. You do not want to delete the row from the grid if something went wrong and the record is still on the database.
$scope.deleteSelected = function(){
angular.forEach($scope.gridApi.selection.getSelectedRows(), function (data, index) {
YourService.delete({
id: data.id
}, function(response) {
$scope.gridOptions.data.splice($scope.gridOptions.data.lastIndexOf(data), 1);
}, function(error) {
// Run any error code here
});
});
}
Related
I explain myself: I have a Sharepoint custom list and I'm using AngularJS to call this list. With the data I obtain from the list, I'm making a "single bar chart" for each item in this list. I'm using jquery.lineProgressbar.js to make the charts.
I'm doing the table with ng-repeat. And I need to provide a different ID name to each "chart div", otherwise the jquery.lineProgressbar.js won't work. Here's my HTML:
<table>
<tr>
<td>Name</td>
<td>Productivity percentage</td>
</tr>
<tr ng-repeat="item in items">
<td>{{item.Name}}</td>
<td>
<!-- The "ng-attr-id" provides the div a different ID depending the name they introduce. i.e.: "chart-Person1" -->
<div ng-attr-id="{{'chart-' + item.Name}}" data-percentage="{{item.Productivity_x0020_percentage}}"></div>
</td>
</tr>
</table>
and my main problem, the SCRIPT:
<script>
//I need to call each chart, one by one like this:
chartFunction('chart-Person1');
chartFunction('chart-Person2');
chartFunction('chart-Person3');
chartFunction('chart-Person4');
//and I need to make this automatically,
//because people will submit new items whenever they want,
//and I can't be updating the script each time someone uploads something.
function chartFunction(elementID) {
var dataPercentage = $("#" + elementID).data('percentage');
//this calls the chart code
$("#" + elementID).LineProgressbar({
//it says that the div selected will have a "percentage" equals to the percentage they wrote in the list.
percentage: dataPercentage
});
}
</script>
I have a Plunker. It is a little different because it has a function which runs the charts only when they're in the viewport, and it doesn't use AngularJS. But it's only so you can see how it works: my Plunker
So, as I said in my code, I need to call each new element added to the sharepoint list, but I can't be creating new calls in my code each time someone uploads an item. Thanks in advance for your help.
I've found the solution to this.
I needed to do it directly in the call of the list (in the Angular code).
<script>
var myApp = angular
.module('myApp', [])
.controller('myController', function ($scope, $http) {
//first I call the Sharepoint List with AngularJS
$http({
method: 'GET',
url: "SiteURL/_api/web/lists/getByTitle('Employees List')/items?$select=*",
headers: { "Accept": "application/json;odata=verbose" }
}).then(function onSuccess(response) {
//If the call is successful I create an empty Array called "peopleArray"
//Here I will store the names of the divs which will run the chart's code
$scope.items = response.data.d.results;
var theItems = $scope.items,
peopleArray = [];
//I run a loop to go through all the items in the Sharepoint list
//I assign a name for each person in the "peopleArray"
for(var i=0; i<theItems.length; i++) {
var currentItem = theItems[i];
peopleArray.push('chart-' + currentItem.Name);
};
//I run another loop, this one goes through the "peopleArray"
//each item executes the function below with the div name assigned in the previous loop
for(var z=0; z<peopleArray.length; z++) {
chartFunction(peopleArray[z]);
}
//and this is the function to make the charts for each person
function chartFunction(elementID) {
var dataPercentage = $("#" + elementID).data('percentage');
$("#" + elementID).LineProgressbar({
percentage:dataPercentage
});
}
}).catch(function onError(response) {
//In case of Error, it will pop an alert
alert("Error! The charts can't be loaded.");
});
});
</script>
This is my HTML:
<button type="button" class="btn btn-primary" ng-hide="ctrl.userProfile.following">Follow</button>
<button type="button" class="btn btn-primary" ng-show="ctrl.userProfile.following">Unfollow</button>
So basically, I want to hide the "Follow" button and show the "Unfollow" button if ctrl.userProfile.following is true, and vise-versa.
This is my back-end:
self.userProfile = {};
function fetchUserProfile() {
$http.get('/users/' + username)
.then(function(response) {
self.userProfile = response.data;
}, function(response) {
self.cerrorMessages = BaseService.accessErrors(response.data);
});
};
fetchUserProfile();
So I get the userProfile and then update self.userProfile with the watching variable (this occurs when I do self.userProfile = response.data. With that said, is there a way for me to tell HTML to not display the buttons until self.userProfile is filled with watching variable?
Create a userProfile.ready flag and use that to control the showing of the Follow and Unfollow buttons.
HTML
<div ng-show="ctrl.userProfile.ready">
<button type="button" ng-hide="ctrl.userProfile.following">Follow</button>
<button type="button" ng-show="ctrl.userProfile.following">Unfollow</button>
</div>
JS
self.userProfile = {};
self.userProfile.ready = false;
function fetchUserProfile() {
self.userProfile.ready = false;
$http.get('/users/' + username)
.then(function(response) {
self.userProfile = response.data;
self.userProfile.ready = true;
}, function(error) {
self.cerrorMessages = BaseService.accessErrors(error.data);
});
};
fetchUserProfile();
There are a few ways of doing this. Here is one:
If you start with an empty object, and are waiting for the promise to resolve, you can set a scope variable that checks the length of the object.
e.g.
self.userProfileLength = Object.keys(self.userProfile).length;
And in the view, do: ng-if="ctrl.userProfileLength"
(Note: Or use ng-show if you want to keep the element in the DOM)
Object.keys returns the keys from the object in an array. Anything over a length of 0 is a truthy value so it will pass the ng-if condition.
Problem Question,
I have a delete method on my cart, so when I press on delete button it delete the item of it. But my view is not getting update whereas item is getting successfully deleted.
//Cart controller
(function() {
var cartController = function($scope,cartService,NotificationService) {
getCart();
function getCart() {
cartService.getCart()
.success(function (cart) {
if (cart != null || cart != 'undefined') {
$scope.cartData = cart;
console.log(cart)
}
})
.error(function (status, data) {
console.log(status);
console.log(data);
})
};
$scope.deleteItem = function (productID) {
cartService.deleteCartItem(productID)
.success(function () {
NotificationService.add("success", "Item deleted from the cart", 3000);
getCart();
})
.error(function (status, data) {
console.log(status);
console.log(data);
})
}
cartController.$inject = ['$scope', 'cartService', 'NotificationService'];
angular.module('cartApp').controller('cartController', cartController);
}
}());
//my view
<div class="mainContainer" ng-controller="cartController">
<tr ng-repeat="cart in cartData.carts" >
<td>
<button ng-click="deleteItem(cart.id)" class="btn btn-primary">Delete</button>
</td>
</tr>
</div>
Please guide me what I am doing wrong.
Add $scope.$apply(); after the ajax call.
$scope.cartData = cart;
console.log(cart);
$scope.$apply();
When working with $scope in angular you will run into this issue when you overwrite an object on $scope (as opposed to modifying properties of that object). As previously mentioned $scope.$apply() will force Angular to reevaluate all your bindings and should cause your UI to update. That being said, making a call to your API to get the entire contents of the cart following a delete operation seems very inefficient here. You either want to send back an empty 200 OK and use that as a trigger to know that it is safe to remove the item client side using splice. The other option would be to send the new cart contents as the body of your 200 OK following a successful delete and at least save yourself an extra round trip.
Add a $scope.$apply() to the end of your call. This will run the angular digest loop and update your view.
Update the $scope.cartData array removing the deleted one on the success method
$scope.cartData.splice($scope.cartData.indexOf(productID), 1 );
This is sort of a follow-up to my previous question. I'm trying to figure out how to edit an existing item that is stored in my Firebase. My items are repeated on the page, and each of them have an "Edit" button next to them.
HTML
<h3>Editing {{ editedProvider.title }}</h3>
<form>
<input ng-model="editedProvider.title">
<button type="submit" ng-click="updateProvider()">Submit</button>
</form>
<div ng-repeat="provider in providers">
<h3>{{ provider.title }}</h3>
<button type="button" ng-click="setEditedProvider()">Edit</button>
</div>
</div>
This is how I'm currently adding an item to my list:
JS
var rootRef = new Firebase(FBURL);
var providersRef = rootRef.child('providers');
$scope.newProvider = {};
$scope.providers = [];
providersRef.on('child_added', function(snapshot) {
$timeout(function() {
var snapshotVal = snapshot.val();
console.log(snapshotVal);
$scope.providers.push({
title: snapshotVal.title,
name: snapshot.name()
});
});
});
$scope.createProvider = function() {
var newProvider = {
title: $scope.title
};
providersRef.push(newProvider);
};
I've then created a function setEditedProvider and binded it to the edit button, that when clicked brings up the edit form for that particular item. When I've made my changes however, I need to run a function called updateProvider, and I'm having problems creating that function.
$scope.editedProvider = null;
$scope.setEditedProvider = function(provider) {
$scope.editedProvider = angular.copy(provider);
}
$scope.updateProvider = function(provider) {
// need to take that edited function and push the updated version inside here
}
Can I utilise Firebase's data snapshot for this, like I am for creating the item?
Some of this is finally clicking for me, I think I understand how it needs to be done, I just can't work out how to achieve it.
Any help with this problem is appreciated. Thanks in advance!
$scope.updateProvider = function(provider) {
providersRef.child(provider.$id).update({tile:Provider.title});
}
I have a table with ng-grid, and the problem is that i'm not sure how to collect the selected row(s) id or variable to pass into my delete function.
here is a quick mockup of what i'm trying to do
http://plnkr.co/edit/zy653RrqHmBiRJ7xDHlV?p=preview
the following code is from my html, a clickable delete button that takes in 2 parameters, the array of checkbox ids and the index at the corresponding table. This delete method was obtained from this tutorial : http://alexpotrykus.com/blog/2013/12/07/angularjs-with-rails-4-part-1/
<div class="btn-group">
<button class="my-btn btn-default button-row-provider-medical-services" ng-click="deleteProviderMedicalService([], $index)">Delete</button>
</button>
</div>
<div class="gridStyle ngGridTable" ng-grid="gridOptions">
</div>
The following code grabs the json data from a url, queries it and returns it. It also contains the delete function that gets called from the controller in the html page.
app.factory('ProviderMedicalService', ['$resource', function($resource) {
function ProviderMedicalService() {
this.service = $resource('/api/provider_medical_services/:providerMedicalServiceId', {providerMedicalServiceId: '#id'});
};
ProviderMedicalService.prototype.all = function() {
return this.service.query();
};
ProviderMedicalService.prototype.delete = function(providerId) {
this.service.remove({providerMedicalServiceId: providerId});
};
return new ProviderMedicalService;
}]);
The following is my controller(not everything, just the most important bits). $scope.provider_medical_services gets the json data and puts it into the ng-grid gridOptions.
After reading the ng-grid docs, i must somehow pass the checkbox ids from the selectedItems array and pass it into html doc to the delete function. Or, i'm just doing this completely wrong, as i hacked this together. Solutions and suggestions are greatly appreciated
(function() {
app.controller('ModalDemoCtrl', ['$scope', 'ProviderMedicalService', '$resource', '$modal', function($scope, ProviderMedicalService, $resource, $modal) {
var checkBoxCellTemplate = '<div class="ngSelectionCell"><input tabindex="-1" class="ngSelectionCheckbox" type="checkbox" ng-checked="row.selected" /></div>';
$scope.provider_medical_services = ProviderMedicalService.all();
$scope.deleteProviderMedicalService = function(ids,idx) {
$scope.provider_medical_services.splice(idx, 1);
return ProviderMedicalService.delete(ids);
};
$scope.gridOptions = {
columnDefs: [
{
cellTemplate: checkBoxCellTemplate,
showSelectionCheckbox: true
},{
field: 'name',
displayName: 'CPT Code/Description'
},{
field: 'cash_price',
displayName: 'Cash Price'
},{
field: 'average_price',
displayName: 'Average Price'
},
],
data: 'provider_medical_services',
selectedItems: []
};
i think the easiest option is pass an (array index) as data-id to your dom, which u can pick it from there.
{{$index}} is a variable you can use in ng-repeat
======= ignore what i said above, since i normaly writes my own custom stuff ======
I just had a look at ng-grid, i took their example. i've added a delete all selected function, as well as someone elses delete current row function ( these is pure angular way ) to see the code, hover over the top right corner < edit in jsbin >
http://jsbin.com/huyodove/1/
Honestsly i don't like it this way, you would be better off use something like lodash to manage your arrays and do your own custom grid. Using foreach to find the row index isn't good performance.
In their doc, it says you can change the row template, and which you should, so you can add the {{index}} to that row, and filter your data through that index rather which is a little bit better. anyway beware of deleting cells after you have filter your table.
I don't quite get much your question, but you can access to selectedItems of ng-grid as following: $scope.gridOptions.$gridScope.selectedItems (see ng-grid API for more information, but technically this array holds the list of selected items in multiple mode - or only one item in single mode)
For your case, the deleteAll() function could be someething like this:
$scope.deleteAll = function() {
$scope.myData = [];
}
The delete() function which delete selected items can be:
$scope.delete = function() {
$.each($scope.gridOptions.$gridScope.selectedItems, function(index, selectedItem) {
//remove the selected item from 'myData' - it is 2-ways binding to any modification to myData will be reflected in ng-grid table
//you could check by either name or unique id of item
});
}