Angularjs state retension - angularjs

I am adding row dynamically using angularjs. But the problem is that I want to retain this state all over the application. For example in view-1 I add one dynamic row to the table and move to view-2 after coming from view-2 the added row should be available. So is there any method to retain the state of view in angularjs. Following is the code I used to add row dynamically:
angular.module('MyApp', [])
.controller('MainController', [ '$scope', function($scope) {
$scope.rows = ['Row 1'];
$scope.counter = 2;
$scope.addRow = function() {
$scope.rows.push('Row ' + $scope.counter);
$scope.counter++;
}
}]);
<body ng-controller="MainController">
Add Row {{counter}}
<table>
<thead>
<tr>
<th width="200">Some Header</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="rowContent in rows">
<td>{{rowContent}}</td>
</tr>
</tbody>
</table>
</body>
Thanks.

Yes. You should save the model used to build the table (with the new rows aswell) to a Service. Then you inject that service in your controllers.
To be able to see a little bit of your code would be nice, though. But here goes an example of how to do this:
DISCLAIMER
Untested example
angular.module('yourapp').factory('MySharedService',function(){
var myTableModel = [];
function addRow(row){
myTableModel.push(row);
return myTableModel;
}
return {
addRow: addRow,
tableModel: myTableModel
}
})
.controller('MyFirstController',['$scope','MySharedService',function($scope,
MySharedService){
$scope.tableModel = MySharedService.tableModel;
$scope.addRow = function(row){
$scope.tableModel = MySharedService.addRow(row);
}
}]).controller('MySecondController',['$scope','MySharedService',function($scope,
MySharedService){...}]);
EDIT:
After researching a bit further on this, I've found a similar question with a couple ways of achieving this and with sample code here
Check it out and see if it helps you.

Related

Angular template doesn't render data from controller

I'm setting up an Angular JS app to consume a Django REST API, and I'm stuck on the rendering of data.
I already asked another question (this), but the solution that I've been given doesn't work.
I was wondering that maybe there is something wrong in the API view, could it be a problem when trying to render the data from the Angular controller?
Anyway, this is my Angular app + template (edited as suggested in the other stackoverflow question)
base.html
<body ng-app="schoolApp" ng-controller="schoolCtrl as vm">
<p>Hello {{vm.name}}!</p>
<div>
<table class="table table-striped">
<thead>
<tr>
<th>Classroom</th>
<th>School</th>
<th>Floor</th>
<th>Academic year</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="classroom in vm.classrooms">
<td>{{classroom.classroom}}</td>
<td>{{classroom.school.school_name}}</td>
<td>{{classroom.floor}}</td>
<td>{{classroom.academic_year}}</td>
</tr>
</tbody>
</table>
</div>
</body>
app.js
var schoolApp = angular.module('schoolApp', ['ngResource']);
schoolApp.factory('Classroom', ['$resource', function($resource) {
return $resource('/classrooms/?format=json', {}, {
query: {
method: 'GET',
isArray: true,
}
});
}]);
schoolApp.controller('schoolCtrl', function($scope, Classroom) {
var vm = this;
vm.name = 'World';
Classroom.query().$promise.then(function(data) {
console.log('Success: '+JSON.stringify(data));
vm.classrooms = data;
}, function (reason) {
console.log('ERROR: '+JSON.stringify(reason));
});
});
I was thinking that maybe there is some problem on the view, so here's the REST API view
class HomePageView(TemplateView):
template_name = 'school_app/base.html'
class StudentViewSet(viewsets.ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
class ClassroomViewSet(viewsets.ModelViewSet):
queryset = Classroom.objects.all()
serializer_class = ClassroomSerializer
What am I doing wrong?
UPDATE:
This is what I get
Data on the console: yes.
Data on the tables: no.
As you are using controllerAs syntax, you have binded all data to controller context. So you could get data on view using its alias like vm.classrooms
<tr ng-repeat="classroom in vm.classrooms">
Have you tried to output in the html the content of the variable vm.classrooms.
You can do it with <pre>{{vm.classrooms|json}}</pre>
It seems to me that you are not binding correctly the variables inside the table,
i can't see it clearly in the picture, it can be {{ classroom.school.academic_year }} ??

Angular $watch just parent object instead of its multiple children

I have a div, listing properties of the object POI = {"address":"Martinsicuro (TE), Italy", "phone":"+39 333 45657", "website':'http://mysite.it"}. The object POI si owned by a Service. The directive's controller has the function getPoi() that gets the POI from the service, and returns it to the directive.
My current HTML is something like this:
<table ng-controller="Controller as ctrl">
<tr> <!-- address -->
<td>{{ctrl.getPoi().address}}</td>
</tr>
<tr> <!-- phone -->
<td>{{ctrl.getPoi().phone}}</td>
</tr>
<tr> <!-- website -->
<td>
<a ng-href="{{ctrl.getPoi().website}}">
{{ctrl.getPoi().website}}
</a>
</td>
</tr>
</table>
The controller
.controller('Controller', function(CurrentPoiService)
{
this.getPoi = function()
{ return CurrentPoiService.POI; }
}
The service
.service('CurrentPoiService', function()
{
this.POI = {"address":"Martinsicuro (TE), Italy", "phone":"+39 333 45657", "website':'http://mysite.it"}
}
In this way I am adding 3 watchers. Is there a way to add just 1 watcher, since it's the same parent object? Here it is a JSFiddle
Thank you
[UPDATE 1]
This is the (still not working) JSFiddle using the solution proposed by #Charlie
[UPDATE 2]
This is the working JSFiddle
As Claies has mentioned in a comment, you should never call your data from
the view through a function this way.
In this scenario you can create a watch for the POI object with the objectEquality argument true to watch the properties of the object in a single $watch. Then find your elements inside the listener and change the value in the way you want.
$scope.$watch('POI', function(){
//Assume that $scope.propertyIndex is the current property to display
angular.element($document[0].querySelector("#myTd" + $scope.propertyIndex)).html(POI.address);
angular.element($document[0].querySelector("#myTd" + $scope.propertyIndex)).html(POI.phone);
//etc...
}, true);
You have a better control this way. But please keep in mind that this method is not suitable if POI is a complex object.
UPDATE:
Here is a working example of showing a random number every second using a watch and a factory. You should be able to learn from this and apply it to your project.
myApp.controller('myController', function($scope, dataSource) {
$scope.poi = {rand: 0};
$scope.$watch('poi', function() {
$('#rand').html($scope.poi.rand);
}, true);
dataSource.open($scope);
});
myApp.factory('dataSource', function($interval) {
return {
open: function(scope){
$interval(function() {
scope.poi.rand = Math.random();
}, 1000);
}
}
});
Try inside your controller :
$scope.POI = ctrl.getPoi();
HTML :
<tr> <!-- address -->
<td>{{POI.address}}</td>
</tr>
<tr> <!-- phone -->
<td>{{POI.phone}}</td>
</tr>

angular edit details using REST($resource) Service

I have a table with result set and there is edit option existing in each row. After clicking on the 'edit' link, i am able to populating the content on the fields.
But how do i edit the existing content using REST Service.
<table class="table-bordered table">
<thead>
<tr>
<th>id</th>
<th>Director</th>
<th>genre</th>
<th>releaseYear</th>
<th>title</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="result in results | orderBy:'_id'">
<td>{{result._id}}</td>
<td>{{result.director}}</td>
<td>{{result.genre}}</td>
<td>{{result.releaseYear}}</td>
<td>{{result.title}}</td>
<td>Edit | Delete</td>
</tr>
</tbody>
</table>
controller
$scope.saveContact = function(){
//save or edit contact
};
I have created in plunker.
content EDIT using REST API
I put it into work. You were close to the solution.
Here is the working plunker
What i did :
1 - I changed your way of getting the element for the form.
HTML
//I give the complete object instead of the id
ng-click="edit(result)"
Controller
//I prefer to pass the entire object
$scope.edit = function(result){
$scope.cineresultsFrm = angular.copy(result);
};
Service
I just removed the service. It wasn't useful anymore.
2 - I used the method of the ressource on your object
Controller
$scope.saveContact = function(){
//The function given to $update() is the .then() function
$scope.cineresultsFrm.$update(function(){
//If the update succeed i update the whole list. Could be done a better way but if you don't have any performance issues that will do the job.
$scope.getMovies();
});
};
I also changed the way you handle the "then" in the promise. But this is just a matter of taste.
$scope.getMovies = function(){
$scope.movieResults = movie.query(function() {
$scope.results = $scope.movieResults;
});
};
$scope.getMovies();
Hope it helped you

Output is concatenated

New click on [Filter] does not clear previous output but adding to exists.
For example, if filtered by "banned" I see the banned users list, next filter by "registered" does not remove the "banned" but adding the "registered" to the end of the table.
In controller $scope.site_users overwritten, but somewhere it still saves the previous filter output.
Why is that happens? May be something on packages side?
Installed packages:
urigo:angular - Angular
angularui:angular-ui-router
accounts-password
accounts-ui
twbs:bootstrap
Removed packages:
insecure
autopublish
Or in code
Controller:
angular.module("sis_admin_am").controller("UsersListCtrl", ['$scope', '$meteor',
function($scope, $meteor){
$scope.filter = function(){
$scope.site_users = '';
$scope.site_users = $meteor.collection(Users).subscribe('site_users_filtered', {status: $scope.userStatus});
};
}
]);
View:
<form ng-submit="filter()">
<button>Filter</button>
<select ng-model="userStatus" >
<option ng-selected="selected">banned</option>
<option>registered</option>
<option>active</option>
</select>
</form>
<p></p>
<table class="table">
<tr class="panel panel-default">
<th>Name</th>
<th>Email</th>
</tr>
<tr ng-repeat="user in site_users">
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
</tr>
</table>
Server part:
Meteor.publish('site_users_filtered', function(options) {
console.log('options:', options);
return Users.find(options);
});
That's because how Subscriptions in Meteor works.
If you add or change a subscription without closing the ones before, it will just add them all together (which is good but you have to be aware of it).
If you want to filter with subscriptions (for security reasons) you should change your code like that:
angular.module("sis_admin_am").controller("UsersListCtrl", ['$scope', '$meteor',
function($scope, $meteor){
var savedSubscriptionHandle = null;
$scope.filter = function(){
savedSubscriptionHandle.stop();
$scope.site_users = '';
$scope.site_users = $meteor.collection(Users);
$scope.$meteorSubscribe('site_users_filtered', {status: $scope.userStatus}).then(function(handle){
savedSubscriptionHandle = handle;
});
};
}
]);
But if you don't mind keeping all the data in the local cache it might be easier to use Angular's filters or Meteor's cursor syntax to filter the display.
More detailed explanation here:
http://angular-meteor.com/tutorial/step_12
I think your problem is, ngSelected NOT necessarly select only one choice of your dropdown.
and that is because,tchnically you should de-select your unwanted userStatus manually as they do in the official doc :
https://docs.angularjs.org/api/ng/directive/ngSelected
You can try to send your ng-model (userState) along to the filter() function and actually filter with that value directly without having to check the scope.

AngularJS calling a function inside a controller with ng-click

I've got a problem with getting my function inside my controller to work properly.
given the following partial:
<div ng-controller="KundeDetailCtrl"><table class="table table-hover">
<thead>
<tr>
<th>Name</th>
<th>InstallationsID</th>
</tr>
</thead>
<tbody >
<tr data-ng-repeat="mandant in kunde.mandanten" ng-click="getMandant(mandant)" >
<td> {{mandant.name}}</td>
<td>{{mandant.id}}</td>
</tr>
</tbody>
</table></div>
I want to be able to click on one row and call the appropriate function in my controller:
var AppControllers = angular.module('AppControllers', []);
AppControllers.controller('KundeDetailCtrl', ['$scope', '$routeParams', 'Kunde',
function($scope, $routeParams, Kunde) {
$scope.kunde = Kunde.get({kundeId: $routeParams.kundeId}, function(kunde) {
});
$scope.getMandant = function(id){
for(var i= 0, l=$scope.kunde.mandanten.length; i<l; i++){
if($scope.kunde.mandanten[i].id == "id")
{
$scope.mandant = $scope.kunde.mandanten[i];
}
}
Location.href='index.html#/kunden/{{kunde._id}}/module'
};
}]);
Actually, I only want to know which row was clicked and hand the object of the clicked row to the next partial which is supposed to display some other data.
The ng-click does not seem to do anything at all. In the console I only see getMandant: null
Can anyone help me with this?
It seems you are comparing the id in the mandaten list to the string "id" rather than the object id:
if($scope.kunde.mandanten[i].id == "id")
You should also consider using === rather than ==, it is the preferred way to compare things in javascript.
It appears you are redirecting to another view in your angular application, any reason not to use the $location service?

Resources