Reputation: 1058
I'm new to Angular and I'm attempting to build a robust todo app for learning purposes. There's probably something basic I'm doing wrong, but can't figure it out. I assume it's something with the way I have my controllers and templates configured. I've tried some of the recommendations found in similar questions but none that solve my issue. I've tried using $scope.$apply()
but I get the "apply/digest already in progress" error.
I'm using ngRoute so when someone goes to /profile
it calls the profileController
and loads in templates/profile.html
. This controller doesn't really do anything other than setup the current user and attach to $rootScope
. Inside of the profile view I have a nested controller called listController
. I'm passing in the List
resource to listController
to make http requests. Everything is working correctly as far as routing and the get/post requests.
Here's a simplified example of my controller:
var myApp = angular.module('todo', ['ngRoute', 'ngResource'])
// config stuff...
.controller('listController', ['$scope', 'List', 'ngDialog', function ($scope, List, ngDialog) {
// This correctly returns all lists for the current user
$scope.lists = List.query();
// Open modal form function
$scope.openModal = function () {
ngDialog.open({
template: 'templates/partials/new-list.html',
className: 'ngdialog-theme-default'
});
};
$scope.createList = function () {
List.save({}, {
name: $scope.list.name,
description: $scope.list.description
}).$promise.then(function(result) {
$scope.lists.push(result);
});
};
}]);
Here's the relevant part of templates/profile.html
which correctly displays all lists retrieved from List.query()
:
<div class="todo-sidebar" ng-controller="listController">
<h3>Your lists <a href="#" ng-click="openModal()"><span>New list</span></a></h3>
<ul>
<li ng-repeat="list in lists">
<a href="#"><span class="list-name">{{list.name}}</span></a>
</li>
</ul>
</div>
The problem is when I call the createList
function from inside my templates/partials/new-list.html
partial:
<div class="dialog-contents" ng-controller="listController">
<h3>New list</h3>
<form ng-submit="createList()">
<div class="form-group">
<label>Name</label>
<input type="text" name="name" ng-model="list.name">
<textarea name="description" ng-model="list.description" rows="10"></textarea>
<button type="submit" class="button">Create list</button>
</div>
</form>
</div>
The form posts correctly and I can see the new list in my database, but the view does not update in real-time. When I console.log($scope)
inside the promise it appears that my new list has been added to the scope.
I have a feeling it's not best practice to attach a controller to multiple elements/templates, but I'm not sure how else to structure this.
Upvotes: 3
Views: 1040
Reputation: 1839
Okay so after a little research I think I have a solution for you. So what is happening is that you're not resolving the close of the dialog box correctly.
For reference here is the link I used:
https://github.com/likeastore/ngDialog#api
Scope
What you're dealing with here is a scope issue. When the dialog box is opened up, it is generating a separate module with it's own controller. This controller's scope is a one-way binding, and will not be seen by the parent scope upon resolution. So this is the why to the reason that your scope is not updating on the parent scope level.
For the how, please see the next section regarding promises.
Promises
To manage the scope at the parent level you're going to need something called a promise function, or in simpler terms a function that happens after the close of the dialog resolves fully. When dealing with the promise function there will be some kind of initial callback that allows you to pass data to the promise, and when you initialize the promise this is when you'll be able to access that data, which will then cooperate with the parent-level scope variables.
For this solution I have provided you a bit of updated code that might be helpful for you.
updated Code
If I'm understanding how your code works along with how the module works your updated functions should look something like the following. I would give this a shot:
var myApp = angular.module('todo', ['ngRoute', 'ngResource'])
// config stuff...
.controller('listController', ['$scope', 'List', 'ngDialog', function ($scope, List, ngDialog) {
// This correctly returns all lists for the current user
$scope.lists = List.query();
// Open modal form function
$scope.openModal = function () {
var dialog = ngDialog.open({
template: 'templates/partials/new-list.html',
className: 'ngdialog-theme-default',
controller : function($scope){
$scope.createList = function(){
dialog.close($scope.list); // where data is the list data
};
}
});
dialog.closePromise.then(function(data){
// at this point data is your list and then you can update the value as you see with like normal
List.save({}, {
name: $scope.list.name,
description: $scope.list.description
}).$promise.then(function(result) {
$scope.lists.push(result);
});
});
};
}]);
Again this is just a rough template for what you'd need to do, but this is how you would implement it nonetheless.
I hope this helps, please ask if you have any more questions.
Upvotes: 1
Reputation: 161
You're dealing with a $scope issue I think. The values are there, but you're not referencing what you think you are. Referencing the "lists" via controllerAs, like so...
<li ng-repeat="list in MyController.lists">
should fix your problem.
Hope that helps.
This will explain it far better than I will be able to. https://github.com/angular/angular.js/wiki/Understanding-Scopes#ngRepeat
Upvotes: 0