AngularJS: Delete clicked elements parent row - angularjs

I have a table of users, each row representing a user.
On the end of each row I have a delete link, which when clicked deletes the user from database.
Now I need to update the table to reflect the changes.
I know how I would do this with jQuery, but how do I do it the angular way?
Do I need to add a ng-model attribute to each row?
This is how I have attached the click event:
<a ng-click="deleteUser(user._id)">Delete</a>
I have a <tr ng-repeat="user in users"></tr> printing out the users. I'm thinking if I remove the user from the model, that might be the way to go.
EDIT: I found now this question, which also answer my question.

Yes you are correct. Use ng-repeat to render the list of users and on delete remove the user from the users list. Since it's a two way binding it will dynamically update the tr's.
Also on ng-click, you would need to call a $http service which will tell the database to delete the required user from DB. Use factory/service to create a $http service.

Related

Structuring an angular app for server side filtering and pagination

tl;dr
What would be best approach for structuring an angular app which supports filtering and sorting on the server side using radio button filters on client side
Context of the app:
I have a sample movie list app, where movies have genre and style to categorize them. They can be sorted based on name, rating, year of release. The backend is very clear, I pass the filters to url in the form of query parameters and data is returned and pagination is also addressed. From the client side I create the url and attach the string params to it. However I have tried few implementations of filters and sorting on the client side and wasnt satisfied. every implementation involves using radio buttons for filters. The following approaches were used by me.
Approaches used:
Create few filters based on genres and styles of movies, launch an event when one radio button is clicked, pass the filter-radio model in the event. Listen for the event in a movieListDirective and then create the url followed by triggering the server call.
Create filters and pass the data in a service, launch an event whenever a radio button is clicked. Listen for the event and receive the data from the service. Create the url and initiate the server call.
Not yet used this approach but thinking of giving it a try
On click of radio button push the data in the browser url in form of query parameters. Listen for url change event inside the directive and trigger the server call
I'm also thinking of using UI router. Create an abstract state for filter and sort button. Put the movieListDirective inside the child state.
I'm just not satisfied with my 2 approaches and think that there's a huge room for improvement. Can anyone please suggest a very scalable approach or something to improve the existing approach which I'm using. Thanks in advance.
**I'm using IONIC. I would like to take advantage of the pull to refresh and infinite scroll features. These have to be put inside the ionic-content directive. Hence the approach used should satisfy this requirement **
Well, if I were you I would change a variable in my $scope and listen its changes to request again with your filters.
I made a Plunker to help you.
https://embed.plnkr.co/cNZ1Um7FycaPBjef5LI1/
In this Plunker, I added the ng-model to my radio buttons. When these radio buttons are selected, they change my variable with their values.
<input type="radio" value="new" ng-model="area">
This radio button above change $scope.area value to "new". Then, my controller listen to this change event and call my $scope.requestAPI function.
$scope.$watch('area', function() {
$scope.requestAPI($scope.area, $scope.category);
});
This function use the values of $scope.area and $scope.category to make a request. Changing their values, you change the request.
It is exactly the feature that you need.

AngularJS: Accessing the changed class of an element after ng-click

I have applied ng-click on an element and within the function, I want to access the DOM element itself. I could do that with :
var element = $document[1].getElementById('<id of the element>');
However, the problem I am facing is that when that element is clicked, it's class changes. But the element I get using the above method is the previous state of the element before the click. How can I get access to the new attributes of an element after the click is performed ?
Update
I am using AngularJS' smart-table for displaying data fetched from backend. The library offers sort functionality but it sorts the data which is already fetched from the DB and is present in front end. I wanted to tweak it so that when I click the sort button, I should be fetching data from the backend and update the rowCollection so that the table refreshes. Now, in order to trigger the API call, I was thinking of using ng-click event on table headers. Also, I need to know whether I need to sort in ascending order or descending order. So, for that, smart-table automatically appends a class sort-ascent or sort-descent to the table header when it is clicked. So, I thought maybe if I can access that, then using the combination of the header column (sort key) and the class (sort order), I can hit the backend API and fetch the appropriate data.
I understand the solution looks more of a hack then a proper way of doing things.
Maybe you should look at this answer : Accessing clicked element in angularjs
You can access by $event.target
<button ng-click="yourSubmit($event)"></button>

Angular UI nested View with different parameter

angular: "1.3.15"
angular-ui-router: "~0.2.13"
TL;DR: How should I provide a value to a nested view?
For brevity's sake I'm going to greatly simplify the application in an attempt to focus on the problem. I have two main views called Customer and Refunds. Each main view has a shared nested view called Notes. The Notes view loads and displays notes relative to the customer at hand using a customerId. The Customer view's route has a customerId, but the Refunds does not. When viewing the Refunds view the notes section is hidden by default. Once the user selects one of the Refunds in the list I want the Notes view to load notes for the customer selected. Since the Notes controller is using $stateParams.customerId it will be empty when loading on the Refunds view. The Refunds controller knows which customerId was selected, but I need some way to tell the nested Notes view which customerId to load.
So far I have come up with a few options, but I'm not sure I like any of them, but here they are.
When the user selects a customer on the refunds page I can navigate to /refunds/:customerId. Don't like that because the page reloads and I have to set the selected item after the page reloads from the stateParams.
After the user selects a customer, use $provide to provide a customerId which gets injected into the NotesController. Don't like that because it's tacky and requires me to do the same thing on the CustomerController.
Caveat: I'm using ControllerAs syntax so scopes don't inherit each other. This prevents me from setting a customerId on the main scope and referencing it in the nested scope.
In your parent scope, store the customerId in the current scope ($scope.customerId = $stateParams.customerId), and on the child scope, get the customer ID from its parent by$scope.$parent.customerId

How to make ng-repeat update view on condition only

Say I have an ng-repeat directive and it displays some data in the table.
When I press a button I send the $http API call to the server and it responds with the new data which is displayed in the same table with a little delay.
I would like ng-repeat to re-render the table view only after this new data has finished loading. But as of now I can see how ng-repeat shows an empty table for a moment and only after that the new data is fetched.
So the question is how does one make Angular update the ng-repeat only on a condition? The event that is fired when the data has finished loading can be an example of such condition.
P. S. I tried prefixing my array with ::, but of no help. It prevented Angular from instant updating the view, but I don't know the way to force the update when I want to.

Angularjs scope not retaining value

Friends..
For my understanding of how routing works in Angular I have created a simple application. This application has only two pages:
1. The first page will display all rows of the employee table. Upon clicking on a particular row, second page will display a form with details of that employee.
The list that is displayed on the first page uses the following code:
<table>
<tr ng-repeat="employee in employees">
<td>{{employee.firstname}} - {{employee. address}}</td>
<td><span ng-click="getSingleEmployeeDetails(employee.id)">Edit</a></td>
</tr>
</table>
I am using the same controller for both these pages and this controller looks like below:
function EmployeeCtrl($scope,$http,Employee,$location,$routeParams) {
// Get all employee details
var data;
Employee.query().then(function(_data) {
$scope.employees = _data.data;
});
// Get Single Employee Details
$scope.getSingleEmployeeDetails = function(id) {
$scope.employee = scope.employees[id];
$location.path('/editemployee/' + id);
}
}
However the issue I am facing is that when the code gets routed to /editemployee/1
for some reason the $scope.employees looses its values.
In other words the form never gets populated with employee details.
What am I doing wrong here ?
This has to do with scoping. The employees are loaded into the EmployeeCtrl when it is instantiated. Once you perform a routing event in getSingleEmployeeDetails() that causes a different controller to load with a different $scope. A $scope that is separate from the $scope inside EmployeeCtrl. One easy way around this is to let EmployeeCtrl handle the functionality of loading/displaying all employees and a single employee without routing to a new controller. The pros here is that it makes it easier to share information, and you don't have to reload the single employee information when the user clicks on a single employee because you can share that information more easily. The con is that you don't get back button navigation to navigate between selections of single employees.
The other option is to let the SingleEmployeeCtrl reload the information when it navigates. The pro is you get back button access again, but the con is you load the information twice (once for loading the full list, and twice for loading the employee information again). This also allows the user to bookmark single employee records, but who bookmarks things anymore?
Others have already explained the fact that a new controller (and $scope) are created when you change routes. Also note that $scope.employees is populated asynchronously, when the promise is resolved. What is likely happening is that getSingleEmployeeDetails() is being called before the promise is resolved, so the employees array is empty.
To solve the problem, I suggest a different architecture.
You have two views/pages. Each view in Angular typically has its own controller. Models/data are typically stored in services, and an API to retrieve and manipulate those models/data is made available/public by the service. A controller just glues everything together: it injects the service(s) it needs, and then references only the models/data that the associated view needs.
So, even though your app is simple, I suggest the above approach: one service (which stores your employee objects), two controllers, two views. In particular, put the query() call into your service (so it will be called once, when the service is created) and store your data in the service. The service API should define functions/methods that return a promise that will eventually contain the desired data (list of employees, or just one). The controllers should use those methods to get a reference to the desired data.
See also Should services expose their asynchronicity? for an example of how to store the data in the service.

Resources