Angular : Pass JSON $http promise to factory - javascript

At the moment, my Angular app looks like this:
Factory in app.js
StoreApp.factory("DataService", function () {
// create store
var myStore = new store();
// create shopping cart
var myCart = new shoppingCart("Store");
// return data object with store and cart
return {
store: myStore,
cart: myCart
};
});
controller.js
function storeController($scope, $http, $routeParams, $location, DataService) {
$scope.store = DataService.store;
$scope.cart = DataService.cart;
// use routing to pick the selected product
if ($routeParams.productUrlTitle != null) {
$scope.product = $scope.store.getProduct($routeParams.productUrlTitle) || $scope.store.getHero($routeParams.productUrlTitle);
}
$scope.predicate = '-price';
$scope.store.isCart = $location.path() == "/cart";
}
In store.js (below) is where my issue is — currently this.products[] takes inline assignments. I need this to instead load an external JSON file (also below). I've tried several things from including/passing the promise to var myStore = new store();, to actually including $http.get() paired with .then() inside of store.js — to no avail.
store.js
function store() {
this.products = [
new product("USD", 20, "https://foo.jpg", "Name", "Description"),
new product("USD", 20, "https://bar.jpg", "Name", "Description"),
];
}
store.prototype.getProduct = function (urlTitle) {
for (var i = 0; i < this.products.length; i++) {
if (this.products[i].urlTitle == urlTitle)
return this.products[i];
}
return null;
}
payload.json
[
{
"currency": "usd",
"cost": 1000,
"image_url": "https://whatever.domain/someimage.jpg",
"id": "xyz",
"name": "A title",
"description": "Some details"
},
...
]
For those interested, my project is based on this: A Shopping Cart Application Built with AngularJS.
Many thanks in advance.
Update
I was able to accomplish what I wanted, but I'm not certain it's the best (Read: correct) way to. In short, I added a new factory called "InventoryService" that I pass to my controller.
app.js
// New Factory Added
StoreApp.factory('InventoryService', ['$http', '$rootScope',
function ($http, $rootScope) {
var inventory = [];
return {
getInventory: function () {
return $http.get('http://localhost/ShoppingCart/payload.json').then(function (response) {
inventory = response;
$rootScope.$broadcast('handleInventoryService', inventory);
return inventory;
})
}
};
}
]);
controller.js
function storeController($scope, $http, $routeParams, $location, InventoryService, DataService) {
$scope.name = 'inventory';
(function () {
InventoryService.getInventory().then(function (inventory) {
$scope.inventory = inventory;
for (var i = 0; i < $scope.inventory.data.length; i++) {
if ($scope.inventory.data[i].id == '11ca3ea26f0e431eb996a401f292581f2') {
DataService.store.hero.push(
new product(
$scope.inventory.data[i].id,
$scope.inventory.data[i].image_url,
$scope.inventory.data[i].name,
$scope.inventory.data[i].description,
$scope.inventory.data[i].cost
)
);
} else {
DataService.store.products.push(
new product(
$scope.inventory.data[i].id,
$scope.inventory.data[i].image_url,
$scope.inventory.data[i].name,
$scope.inventory.data[i].description,
$scope.inventory.data[i].cost
)
);
}
}
// get store and cart from service
$scope.store = DataService.store;
$scope.cart = DataService.cart;
...
store.html partial
<div ng-include src="'partials/header.html'"></div>
<div ng-repeat="product in store.hero" class="row-fluid">
<div class="span12">
<div class="span4">
<a href="#/products/{{product.urlTitle}}">
<img class="img-polaroid" ng-src="{{product.image_url}}" title="{{product.name}}" />
</a>
</div>
<div class="span8">
<h1 class="tango-tang weight-100">
{{product.name}}
</h1>
<hr />
<div class="row-fluid">
<div class="span7">
<p>
{{product.description}}
</p>
</div>
<div class="span5">
<div class="well">
<h1 class="weight-300 text-center">
{{product.price | currency}}
</h1>
</div>
<button class="btn btn-success btn-medium btn-block" ng-click="cart.addItem(product.sku, product.image_url, product.name, product.price, 1)">
<i class="icon-plus"></i> Add to Cart
</button>
<a href="#/products/{{product.urlTitle}}" class="btn btn-block">
<i class="icon-list"></i> Details
</a>
</div>
</div>
</div>
</div>
</div>

As I outlined in the comment, the InventoryService isn't necessary in your case, $q and $http.get are enough.
Quoted from comments:
You may try to make products and hero both promises, later when HTTP responded, resolve two deferred objects at once.
Code:
App.factory('DataService', function($http, $q) {
function Store() {
var heroDeferred = $q.defer();
var productsDeferred = $q.defer();
this.hero = heroDeferred.promise;
this.products = productsDeferred.promise;
$http.get('/path/to/payload.json').success(function(data) {
var hero = [];
var products = [];
for (var i = 0, len = data.length; i < len; i++) {
var prod = data[i];
if (prod.id === 'xyz') {
hero.push(prod);
} else {
products.push(prod);
}
}
heroDeferred.resolve(hero);
productsDeferred.resolve(products);
});
}
Store.prototype.getProduct = function(urlTitle) {
return this.products.then(function(products) {
for (var i = 0; i < products.length; i++) { // MUST use products, it's the real value; this.products is a promise
if (products[i].urlTitle == urlTitle)
return products[i];
}
return null;
});
};
...
return {
store: new Store()
...
};
});
http://plnkr.co/edit/qff7HYyJnSdEUngeOWVb

Related

#ModelAttribute in my REST comes empty

I am trying to pass data through <select multiple> from HTML to my RESTful.
That data is an array of String. I don't know why when it comes to my backend it's empty.
This is my REST:
#PutMapping("/events")
#Timed
public ResponseEntity<Event> updateEvent(#RequestBody Event event, #ModelAttribute("attendeesToParse") ArrayList<String> attendeesToParse) throws URISyntaxException {
//Some code
}
This is my HTML:
<div class="form-group">
<label>Attendees</label>
<select class="form-control" multiple name="attendeesToParse" ng-model="vm.usernames"
ng-options="customUser as customUser.username for customUser in vm.customusers">
<option value=""></option>
</select>
</div>
I tried to fix this one for days, I googled it so much but I found no solutions. Please help me.
I can not change my HTML into a JSP due to my project's structure and business logic.
Why does it come empty? If I try to show some logs I see an empty array [].
UPDATE
My HTML form call:
<form name="editForm" role="form" novalidate ng-submit="vm.save()">
<!-- some code -->
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" ng-click="vm.clear()">
<span class="glyphicon glyphicon-ban-circle"></span> <span data-translate="entity.action.cancel">Cancel</span>
</button>
<button type="submit" ng-disabled="editForm.$invalid || vm.isSaving" class="btn btn-primary">
<span class="glyphicon glyphicon-save"></span> <span data-translate="entity.action.save">Save</span>
</button>
</div>
</form>
My event-dialog-controller.js: (is the .js controller that works with form)
(function() {
'use strict';
angular
.module('businessRequestApp')
.controller('EventDialogController', EventDialogController);
EventDialogController.$inject = ['$timeout', '$scope', '$stateParams', '$uibModalInstance', '$q', 'entity', 'Event', 'Desk', 'CustomUser'];
function EventDialogController ($timeout, $scope, $stateParams, $uibModalInstance, $q, entity, Event, Desk, CustomUser) {
var vm = this;
vm.event = entity;
vm.clear = clear;
vm.datePickerOpenStatus = {};
vm.openCalendar = openCalendar;
vm.save = save;
vm.reftables = Desk.query({filter: 'event-is-null'});
$q.all([vm.event.$promise, vm.reftables.$promise]).then(function() {
if (!vm.event.refTable || !vm.event.refTable.id) {
return $q.reject();
}
return Desk.get({id : vm.event.refTable.id}).$promise;
}).then(function(refTable) {
vm.reftables.push(refTable);
});
vm.customusers = CustomUser.query();
$timeout(function (){
angular.element('.form-group:eq(1)>input').focus();
});
function clear () {
$uibModalInstance.dismiss('cancel');
}
function save () {
vm.isSaving = true;
if (vm.event.id !== null) {
Event.update(vm.event, onSaveSuccess, onSaveError);
} else {
Event.save(vm.event, onSaveSuccess, onSaveError);
}
}
function onSaveSuccess (result) {
$scope.$emit('businessRequestApp:eventUpdate', result);
$uibModalInstance.close(result);
vm.isSaving = false;
}
function onSaveError () {
vm.isSaving = false;
}
vm.datePickerOpenStatus.date = false;
function openCalendar (date) {
vm.datePickerOpenStatus[date] = true;
}
}
})();
My event-service.js:
(function() {
'use strict';
angular
.module('businessRequestApp')
.factory('Event', Event);
Event.$inject = ['$resource', 'DateUtils'];
function Event ($resource, DateUtils) {
var resourceUrl = 'api/events/:id';
return $resource(resourceUrl, {}, {
'query': { method: 'GET', isArray: true},
'get': {
method: 'GET',
transformResponse: function (data) {
if (data) {
data = angular.fromJson(data);
data.date = DateUtils.convertLocalDateFromServer(data.date);
}
return data;
}
},
'update': {
method: 'PUT',
transformRequest: function (data) {
var copy = angular.copy(data);
copy.date = DateUtils.convertLocalDateToServer(copy.date);
return angular.toJson(copy);
}
},
'save': {
method: 'POST',
transformRequest: function (data) {
var copy = angular.copy(data);
copy.date = DateUtils.convertLocalDateToServer(copy.date);
return angular.toJson(copy);
}
}
});
}
})();
My event.controller.js:
(function () {
'use strict';
angular
.module('businessRequestApp')
.controller('EventController', EventController);
EventController.$inject = ['Event', 'CustomUser', '$scope'];
function EventController(Event, CustomUser, $scope) {
var vm = this;
vm.events = [];
vm.customUsers = [];
vm.usernames = ["test1", "test2", "test3"];
$scope.allCustomUsers = [];
loadAll();
function loadAll() {
Event.query(function (result) {
vm.events = result;
vm.searchQuery = null;
});
CustomUser.query(function (result) {
vm.customUsers = result;
vm.searchQuery = null;
for (var i = 0; i < vm.customUsers.length; i++) {
$scope.allCustomUsers.push(vm.customUsers[i].username);
}
});
}
}
})();
If you're using angularJS, you can't data bind data with #ModelAttribute, because #ModelAttribute exists only with template engines such as JSP, and AngularJS is not a template engine within Spring. Try instead to use #RequestBody on String parameter, and then extract the data using Jackson.
One more issue, How exactly do you pass your values from front to back? I don't see any $http angularJS call, and no HTML form with POST method.

Angular $scope is not available in the HTML Template but I can see it in console log?

I have been following some online tutorials and using the angularjs-template to get started with Angular. I can't get the page (html template) to update with the controller. I think there is a problem with the way I have set up the controller as the values are not available to the html template.
I have been trying to follow some of the best practive guides which suggested to wrap my components in an 'Invoked Function Expression' and to seperate out the controller, service and service manager. However, I think I have made a bit of a hash of this and need some help to figure out what I am doing wrong.
With the console I can see that $scope.metric contains the information I want. For me this means that the controller has successfully pulled the data back from my API via the metricService. However I can't seem to have the results printed back onto the html page e.g. metric.id.
Any help appreciated - I am at the end of my wits trying to figure this out.
metric.html
<div class="panel panel-primary">
<div class="panel-body">
<!-- Try First Way to Print Results -->
Id: <span ng-bind="metric.id"></span></br>
Name:<input type="text" ng-model="metric.metadata.name" /></br>
<!-- Try Second Way to Print Results -->
<p data-ng-repeat="thing in ::MEC.metric track by $index">
{{$index + 1}}. <span>{{thing.metadata.name}}</span>
<span class="glyphicon glyphicon-info-sign"></span>
</a>
</p>
<!-- Try Third Way to Print Results -->
Id: <span ng-bind="Metric.metricId"></span></br>
Id: <span ng-bind="Metric.id"></span></br>
Id: <span ng-bind="metricService.id"></span></br>
<!-- Try Fourth Way to Print Results -->
Id: <strong>{{::MEC.metric.id}}</strong></br>
Name: <strong>{{::MEC.metric.metadata.name}}</strong></br>
Height: <strong>{{::MEC.metric.type}}</strong>
</div>
metricController.js
(function () {
'use strict';
angular.module('app.metric', ['app.metricService', 'app.metricManager'])
.controller('MetricController', MetricController)
MetricController.$inject = ['$scope', 'metricManager', '$log'];
function MetricController($scope, metricManager, $log) {
metricManager.getMetric(0).then(function(metric) {
$scope.metric = metric
$log.info('$scope.metric printed to console below:');
$log.info($scope.metric);
})
}
})();
metricService.js
(function () {
'use strict';
angular.module('app.metricService', [])
.factory('Metric', ['$http', '$log', function($http, $log) {
function Metric(metricData) {
if (metricData) {
this.setData(metricData);
}
// Some other initializations related to book
};
Metric.prototype = {
setData: function(metricData) {
angular.extend(this, metricData);
},
delete: function() {
$http.delete('https://n4nite-api-n4nite.c9users.io/v1/imm/metrics/' + metricId);
},
update: function() {
$http.put('https://n4nite-api-n4nite.c9users.io/v1/imm/metrics/' + metricId, this);
},
hasMetadata: function() {
if (!this.metric.metadata || this.metric.metadata.length === 0) {
return false;
}
return this.metric.metadata.some(function(metadata) {
return true
});
}
};
return Metric;
}]);
})();
metricManager.js
(function () {
'use strict';
angular.module('app.metricManager', [])
.factory('metricManager', ['$http', '$q', 'Metric', function($http, $q, Metric) {
var metricManager = {
_pool: {},
_retrieveInstance: function(metricId, metricData) {
var instance = this._pool[metricId];
if (instance) {
instance.setData(metricData);
} else {
instance = new Metric(metricData);
this._pool[metricId] = instance;
}
return instance;
},
_search: function(metricId) {
return this._pool[metricId];
},
_load: function(metricId, deferred) {
var scope = this;
$http.get('https://n4nite-api-n4nite.c9users.io/v1/imm/metrics/' + metricId).then(successCallback, errorCallback)
function successCallback(metricData){
//success code
var metric = scope._retrieveInstance(metricData.id, metricData);
deferred.resolve(metric);
};
function errorCallback(error){
//error code
deferred.reject();
}
},
/* Public Methods */
/* Use this function in order to get a metric instance by it's id */
getMetric: function(metricId) {
var deferred = $q.defer();
var metric = this._search(metricId);
if (metric) {
deferred.resolve(metric);
} else {
this._load(metricId, deferred);
}
return deferred.promise;
},
/* Use this function in order to get instances of all the metrics */
loadAllMetrics: function() {
var deferred = $q.defer();
var scope = this;
$http.get('ourserver/books')
.success(function(metricsArray) {
var metrics = [];
metricsArray.forEach(function(metricData) {
var metric = scope._retrieveInstance(metricData.id, metricData);
metrics.push(metric);
});
deferred.resolve(metrics);
})
.error(function() {
deferred.reject();
});
return deferred.promise;
},
/* This function is useful when we got somehow the metric data and we wish to store it or update the pool and get a metric instance in return */
setMetric: function(metricData) {
var scope = this;
var metric = this._search(metricData.id);
if (metric) {
metric.setData(metricData);
} else {
metric = scope._retrieveInstance(metricData);
}
return metric;
},
};
return metricManager;
}]);
})();
Snippet from App.routes
.state('root.metric', {
url: 'metric',
data: {
title: 'Metric',
breadcrumb: 'Metric'
},
views: {
'content#': {
templateUrl: 'core/features/metric/metric.html',
controller: 'MetricController',
controllerAs: 'MEC'
}
}
})
Console
You are mixing two concepts controller alias and $scope, in your case you are creating controller alias as MEC using controllerAs. If you are using controller alias then this will work fine for you :
function MetricController($scope, metricManager, $log) {
var MEC = this;
metricManager.getMetric(0).then(function(metric) {
MEC.metric = metric
$log.info('$scope.metric printed to console below:');
$log.info($scope.metric);
})
}
If you don't want to use controller alias and share data between view and controller via $scope then in your view you should use something like this {{::metric.metadata.name}} and controller function should stay as it is.
PS: If you are using alias then MEC in var MEC = this can be MEC or abc or any name you like but convention is to use var vm = this and controllerAs: 'vm'. If you have controllerAs: 'xyz' then in your view xyz should be used to access model.
Problem with your view HTML, you need to use proper Angular expressions while binding. When you want use ::MEC alias name you need to mark your controller with as keyowrd, like ng-controller="xyz as MEC". And checkout working Plunker
<div class="panel panel-primary">
<div class="panel-body">
<!-- Try First Way to Print Results -->
Id: <span ng-bind="metric.id"></span>
<br> Name1:
<input type="text" ng-model="metric.metadata.name" />
<br><br><br><br>
<!-- Try Second Way to Print Results -->
<p data-ng-repeat="thing in [metric] track by $index">
{{$index + 1}}. <span>{{thing.metadata.name}}</span>
<span class="glyphicon glyphicon-info-sign"></span>
</p><br><br><br>
<!-- Try Third Way to Print Results -->
Id: <span ng-bind="metric.metricId"></span>
<br> Id: <span ng-bind="metric.id"></span>
<br><br><br>
<!-- Try Fourth Way to Print Results -->
Id: <strong>{{::metric.id}}</strong>
<br> Name: <strong>{{::metric.metadata.name}}</strong>
<br> Height: <strong>{{::metric.type}}</strong>
</div>
</div>

Want to refer to the variable in ng-repeat in another div ng-if. AngularJS

I have fetched docs from my database. now what I want to do is based on different doc.statuses, want to display different messages. How to go about it?
<p>
<a target="_blank" style="margin-right:5px" ng-repeat="doc in homeCtrl.getDocs(docType.objectId)" href="{{doc.document.url}}">
<div ng-if="doc.status == 'approved'">Hello</div>
<span class="label label-success"><i class="glyphicon glyphicon-hourglass"></i>{{doc.status}}</span>
<br>{{doc.comment}}<br>
</a>
</p>
so the ng-if in the div is not working. How to refer to the doc used in ng-repeat?
EDIT:
I still can't figure out. My controller looks like this(I'm using a Parse backend)
The controller looks like this
class HomeController {
constructor($scope, $state, itemsService, $location, $ionicLoading) {
'ngInject';
const self = this;
self.UserDocument = Parse.Object.extend('UserDocument');
self.$scope = $scope;
self.$scope.user = {};
self.$scope.objUserDocument = {};
self.$scope.userDocumentTypes = [];
self.loading = $ionicLoading;
// self.$scope.docs = [];
$scope.$on("$ionicView.beforeEnter", function(event, data) {
if (!Parse.User.current()) {
$location.url('/signup');
} else {
// self.$scope.user = window.buddy;
self._getDocumentTypes();
// self.$scope.user.firstName = objUser.get('firstName');
// self.$scope.user.lastName = objUser.get('lastName');
// console.log(objUser.get('docs'));
}
});
window.homeCtrl = this;
}
getDocs(id) {
const self = this;
if (self.$scope.user.docs && self.$scope.user.docs.length) {
var docs = self.$scope.user.docs.filter(d => id == d.docType.objectId);
return docs;
} else {
return [];
}
}
}
export default HomeController;
````
ng-if works fine:
HTML:
<div ng-repeat="item in items">
<span>{{item.id}}</span>
<span ng-if="item.status === 'approved'">approved</span>
<span ng-if="item.status === 'rejected'">rejected</span>
</div>
JS:
angular.module('myApp', [])
.controller('myCtrl', ['$scope', function($scope) {
$scope.items = [
{status: 'approved', id: 1},
{status: 'approved', id: 2},
{status: 'rejected', id: 3},
{status: 'rejected', id: 4}
]
}])
Here is the plnkr: http://plnkr.co/edit/wIX46rZHBNGHdv1S3LKg?p=preview
Try to move the function that retrieves the docs inside you controller and pass the result to ng-repeat instead.
ng-repeat="doc in docs"
and
.controller('YourController', function($scope) {
$scope.docs = getDocs(id);
});

$scope value is null in DOM

I am attempting to use ng-repeat with AngularJS but I am not getting the result of my scope in my DOM. Can anyone see the issue? I have been trying to troubleshoot this for hours and hours now and "players" is always null.
Here is my html:
<body ng-controller="CoachCtrl" >
<div class="mdl-tabs mdl-js-tabs mdl-js-ripple-effect">
<div class="mdl-tabs__tab-bar">
Starks
Lannisters
Targaryens
</div>
<div class="mdl-tabs__panel is-active" id="coach" >
<p>Number of players {{ players.length }}</p>
<table class="table">
<tr>
<th>Firstname
</th>
<th>Lastname
</th>
<th>Tryout Date
</th>
</tr>
<tr ng-repeat="kid in players" >
<td>{{ kid.firstname }}
</td>
<td>{{ kid.lastname }}
</td>
<td>{{ kid.tryout_date }}
</td>
</tr>
</table>
</div>
</div>
and here is my js:
'use strict';
angular.module('myApp.coach', ['ngRoute', 'firebase'])
// Declared route
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/coach', {
templateUrl: 'coach/coach.html',
controller: 'CoachCtrl'
});
}])
// Home controller
.controller("CoachCtrl", ["$scope", "$firebaseAuth", "$location",
function($scope, $firebaseAuth, $location) {
var ref = new Firebase("https://intense-heat-2545.firebaseio.com");
var authData = ref.getAuth();
if(authData){
console.log("User is "+authData.uid+" and is logged in with "+authData.provider);
var league = new Firebase("https://intense-heat-2545.firebaseio.com/users/"+authData.uid+"/league");
league.on("value", function(snapshot){
console.log("League ID = "+snapshot.val());
var leagueVal = snapshot.val();
var playerlist = new Firebase("https://blahblah.firebaseio.com/"+leagueVal+"/players");
$scope.players = [];
$scope.players.push({firstname:'John', lastname:'B', tryout_date:'2015-11-30'});
$scope.players.push({firstname: 'Marty', lastname: 'B', tryout_date: '2015-12-01'});
playerlist.on("child_added", function(snapshot){
//console.log("players ="+snapshot.val());
var player = snapshot.val();
console.log("Firstname ="+player.firstname);
var first = player.firstname;
var last = player.lastname;
var tyd = player.tryout_date;
console.log('player data ='+first+last+tyd);
$scope.players.push({ firstname: first, lastname: last, tryout_date: tyd });
var len = $scope.players.length;
for (var i = 0; i < len; i+=1){
if (1 === len){
console.log("player name = "+$scope.players[i].firstname);
}
}
console.log("players len ="+$scope.players.length);
}, function(error){
console.log("Error getting player info: "+error.code);
});
console.log("players ="+$scope.players[1].firstname+" len= "+$scope.players.length);
}, function(error){
console.log("Erro ="+error.code);
});
} else {
console.log("User is not logged in.");
$location.path('/signin');
}
}
]);
Three things.
The with the regular Firebase SDK Angular doesn't know when to run $digest.
Use $firebaseArray() rather than manipulating your own.
Use resolve() in the router to inject the user with $firebaseAuth().$waitForAuth().
-
var rootRef = new Firebase("https://<my-firebase-app>.firebaseio.com");
var leagueRef = rootRef.child("users").child(authData.uid).child("league");
// read it one time
leagueRef.once('value', function(snap) {
var leagueVal = snapshot.val();
var playerList = rootRef.child(leagueVal).child("players");
// $firebaseArray() will synchronize child events into an array
// Each update will know how to update $digest as well, which
// will keep the view updated.
$scope.players = $firebaseArray(playerList);
});
Your controller code would be greatly simplified if you use resolve in the router.
.constant('FBURL', '<my-firebase-app>')
.service('RootRef', ['FBURL', Firebase)
.factory('Auth', function($firebaseAuth, RootRef) {
return $firebaseAuth(RootRef);
})
.factory('UserLeague', function(RootRef) {
return function(uid) {
var leagueRef = RootRef.child("user").child(uid).child("league");
var deferred = $q.defer();
leagueRef.once(function(snap) {
deferred.resolve(snap.val());
});
return deferred.promise;
}
})
.config(function($routeProvider) {
$routeProvider.when('/coach', {
templateUrl: 'coach/coach.html',
controller: 'CoachCtrl',
resolve: {
leagueVal: function(UserLeague, Auth) {
var authData = Auth.$getUser();
return UserLeague(authData.uid);
},
authData: function(Auth) {
return Auth.$waitForAuth();
}
}
});
})
.controller("CoachCtrl", function($scope, leagueVal, authData, RootRef) {
// no need to check for a user because authData is injected
// use the resolved leagueVal to create a ref
var playerList = RootRef.child(leagueVal).child("players");
// synchronize the players to an array
$scope.players = $firebaseArray(playerList);
});

AngularsJS list and edit with 2 controllers

I try to do my first angularjs application, but i have a problem. I have 2 controllers (and i would like to keep 2): the first to list items, the second to edit or create an item.
When I save an item, or create a new item, i can't edit another or create another, after to do one action the form can't load or save... The problem seems to be this line :
$scope.editPlace = {};
But I don't understand why...
DEMO :
http://jsfiddle.net/cxL7qmke/
HTML:
<div ng-app="mapApp">
<div ng-controller="EditPlaceCtrl">
<form name="editPlaceForm">
<fieldset>
<label for="title">Title:</label>
<input id="title" type="text" ng-model="editPlace.title">
<input type="hidden" ng-model="editPlace.id" />
<button type="submit" ng-click="savePlace()">Save</button>
</fieldset>
</form>
</div>
<section ng-controller="PlaceCtrl">
<ul>
<li ng-repeat="place in places">
<label>{{place.title}} edit</label>
</li>
</ul>
</section>
</div>
JS :
var mapApp = angular.module('mapApp', []);
mapApp.controller('PlaceCtrl', function ($scope, $rootScope, placeService) {
$scope.places = placeService.getAll();
$scope.edit = function (id) {
$rootScope.editPlace = angular.copy(placeService.get(id));
}
});
mapApp.controller('EditPlaceCtrl', function ($scope, placeService) {
$scope.savePlace = function () {
placeService.save($scope.editPlace);
$scope.editPlace = {};
}
});
mapApp.service('placeService', function ($filter) {
var uid = 3;
var places = [
{ id: 1, title: 'Item1', lat: 43.123, lng: -89.123 },
{ id: 2, title: 'Item2', lat: 43.321, lng: -89.321 }
];
this.getAll = function () {
return places;
}
this.get = function (id) {
var place, i;
for (i in places) {
if (places[i].id === id) {
return places[i];
}
}
return false;
};
this.save = function (place) {
if (place.id == null) {
place.id = this.uid++;
places.push(place);
} else {
for (i in places) {
if (places[i].id == place.id) {
places[i] = place;
}
}
}
};
});
I've made few changes and seems to work for me please see here
http://jsfiddle.net/m9bevovy/
in your service I've added
this.newPlace = {};
this.setNew = function (id) {
this.newPlace = this.get(id);
};
and your controllers :
mapApp.controller('PlaceCtrl', function ($scope, $rootScope, placeService) {
$scope.places = placeService.getAll();
$scope.edit = function (id) {
placeService.setNew(id);
}
});
mapApp.controller('EditPlaceCtrl', function ($scope, placeService) {
$scope.placeService = placeService;
$scope.savePlace = function () {
placeService.save($scope.placeService.newPlace);
$scope.placeService.newPlace = {};
}
});
You are using both $scope and $rootScope to hold the reference to editPlace.
If you want to use the $rootScope, use this in your savePlace function:
$rootScope.editPlace = {};
Instead of:
$scope.editPlace = {};
Here`s the working fiddle

Categories

Resources