I've been creating a contact list website and have just begun trying to implement an add contact function. So far I have created the page using a form and input elements and then use ng-click to call a function which theoretically would add an object containing these input values into an already-existing array in the controller. For some reason this doesn't work and nothing is added.
In particular, I'm having trouble with the js/app.js file and the $scope.saveContact = function() in relation to the partial/edit.html webpage. Clicking the "Confirm button" when trying to add a contact calls the saveContact function, but the results are not stored properly. Any help is appreciated.
In my HTML I have this code (which calls the saveContact() function in my controller.
<a href="#/"><div class="confirm col-xs-6" ng-click="saveContact()">
<h3>Confirm</h3>
</div></a>
In my app.js file I have a declaration of an empty object and an array containing objects that already have values (used to display the contacts that are already created). I'm trying to add to these contacts using .push() but it for some reason it doesn't work.
$scope.contact = { ... } //empty object that gets inputs from HTML
$scope.contacts = [ { ... }, ... ];
$scope.saveContact = function(){
$scope.contacts.push($scope.contact);
};
This bottom function fails to push the contact object to the contacts array and I don't understand why.
This is happening as you have assigned same controller to all your routes. Your saveContact function is working fine, its pushing the object to the array. As soon as the route changes, a new instance of the controller is created and hence the added object is lost. You should create a service(singleton) to store the object and inject the service as a dependency to the controller. In this way the array will persist until the page load.
app.service("storeContact", function(){
var contacts = [];
this.setContact = function(cnt){
contacts.push(cnt)
};
this.getContact = function(){
return contacts;
}
});
And inject it in the controller and use the setContact and getContact methods to update the contact array and retrieve the contact array.
Ideally, you should have separate controllers for your route.
The issue is in your app.config code. You are using the same controller for all your templates.
This is not required since you have already mentioned the same in ng-controller attached with body
<body ng-controller="AppController">
<div ng-view></div>
<script src="js/app.js"></script>
</body>
Using same controller for all your routes is essentially (re)instantiating the controllers when the route is changed and thats the reason why $scope.contacts.push($scope.contact); is ineffective for the route / when called from /add.
contactListApp.config(['$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
controller: 'AppController',
controllerAs: 'list',
templateUrl: 'partials/list.html'
})
.when('/add', {
controller: 'AppController',
controllerAs: 'add',
templateUrl: 'partials/edit.html'
})
.when('/edit/:id', {
controller: 'AppController',
controllerAs: 'edit',
templateUrl: 'partials/edit.html'
})
.otherwise({
redirectTo: '/'
});
}]);
Workaround:
Either use separate controllers for separate routes and use a service to store the object
OR
Simply remove the controller and controller as from your route config and you are good to go.
Updated config:
contactListApp.config(['$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: 'partials/list.html'
})
.when('/add', {
templateUrl: 'partials/edit.html'
})
.when('/edit/:id', {
templateUrl: 'partials/edit.html'
})
.otherwise({
redirectTo: '/'
});
}]);
Related
i'm investigating if i can have what the title says.
Here's my thought.
Let's assume that i've got this routes:
.when('/', {
templateUrl : 'partials/homepage.html',
})
.when('/test', {
templateUrl : 'partials/test.html',
})
.when('/page/:pageID', {
templateUrl : 'partials/page.html',
})
.when('/page/single/:pageID', {
templateUrl : 'partials/page-single.html',
})
Until now i had the opportunity to add the templateUrl as also the controller details in the route and everything was working just fine.
Now the app is changed and there is only one controller with all the information needed and must remain one controller. And the routes will be something like that:
.when('/:templateName/:pageID', {
controller: 'myCtrl'
})
Can i set from the controller the template id by getting the templateName parameter? And if so how about the last route example /page/single/:pageID? How can i know that there is a second option in route?
I can take the templateName parameter and see it changing with the $routeChangeSuccess method but i cannot find any way to set the template on the fly.
Any ideas?
One solution could be the following one:
angular.module('myapp', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/:templateName/:pageId', {
templateUrl: function(urlattr){
return '/pages/' + urlattr.templateName + '.html';
},
controller: 'YourCtrl'
});
}
]);
From the AngularJs 1.3 Documentation:
templateUrl – {string|function()} – path or function that returns a path to an html template that should be used by ngView.
If templateUrl is a function, it will be called with the following parameters:
Array.<Object> - route parameters extracted from the current $location.path() by applying the current route
I would move your singleton logic from your controller to a service. Since you didn't provide much code below is an example to give you an idea how it could work.
app.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'partials/homepage.html',
controller: 'SingleController'
})
.when('/test', {
templateUrl: 'partials/test.html',
controller: 'SingleController'
})
.when('/page/:pageId', {
templateUrl: 'partials/page.html',
controller: 'SingleController'
});
});
app.provider('appState', function() {
this.$get = [function() {
return {
data: {}
};
}];
});
app.controller('SingleController', function ($scope, appState) {
$scope.data = appState.data;
});
But if it must be a singleton controller you actually could use the ng-controller directive before your ng-view directive so it becomes a $rootScope like scope for all your views. After that just add empty function wrappers in your $routeProvider for the controllers.
I'm developping an ionic application and when using angular for login my controller is called twice,
I've looked through all the others similar questions but didn't find a solution .
The problem is even when I remove the ng-controller="LoginCtrl as lgnCtrl"
I get my controller called once but without two-way databinding.
here is my route file :
$stateProvider
.state('login', {
url: "/login",
views: {
'main': {
templateUrl: "app/user/loginView.html",
controller: "LoginCtrl",
controllerAs: "lgnCtrl"
}
}
})
$urlRouterProvider.otherwise('/login');
here is my controller
angular.module('starter.controllers')
.controller('LoginCtrl', LoginCtrl);
function LoginCtrl($state, $storage, $translate, $ionicPopup, LoginService, messageService) {
var lgnCtrl = this;
console.log("user dash 1zz");
return lgnCtrl;
}
and here is my views:
loginView.html :
<ion-view view-title="loginView" id="signinBlk">
<ion-content>
<div class="list list col span_1_of_2 " ng-controller="LoginCtrl as lgnCtrl">
</div>
</ion-content>
</ion-view>
index.html:
<body ng-app="starter">
<ion-nav-view name="main"></ion-nav-view>
</body>
if you already define your controller in route you dont need to define controller in html template remove the ng-controller attribute with value form html template then run it will run just once
Instead of having this
ng-controller="LoginCtrl as lgnCtrl"
in html, we can have this in the controller when the route is defined with a controller, for example in the controller, it will go like this
$routeProvider
.when("/", { templateUrl: "views/abc.html", controller: "LoginCtrl as lgnCtrl", caseInsensitiveMatch: true });
it worked like a charm
the functions in the controller are only called once.
I have the following Angular Module, Routes and Controllers inside my index.js file. Nothing complex. So far I load this one javascript file into my Index.html file and everything work fine so far as I have the ng-app & ng-view in the Index.html file. Simple enough
// /ng-modules/render-index.js
angular
.module("homeIndex", ["ngRoute"])
.config(config)
.controller("homeController", homeController)
.controller("aboutController", aboutController);
function config($routeProvider) {
$routeProvider
.when("/", {
templateUrl: "/ng-templates/homeView.html",
controller: "homeController",
controllerAs: "vm"
})
.when("/about", {
templateUrl: "/ng-templates/aboutView.html",
controller: "aboutController",
controllerAs: "vm"
})
.otherwise({ redirectTo: "/" });
};
function homeController() {
var vm = this;
vm.title = "Home Page";
};
function aboutController() {
var vm = this;
vm.title = "About Us";
};
Now I understand that to break this apart at this point in time would be silly because if this was all I was using angular for, why not just keep it all in one javascript file. Understood, But I want to know how to separate these things properly at this level so that I have a basic understanding.
Here is what I want to do. I want to separate the two controllers (homeController & aboutController) to their own files. I also want to know what to do with the routes. DO they get moved into their own javascript file, do they stay in the index.js file? I want to assume that these two controllers will eventually do something complex and therefore I am separating them now.
QUESTION:
Using the (Controller as syntax) How exactly do I do this and what does the index.js file look like and the two home.js and about.js files look like when they have been separated?
What I have tried:
I have tried to put each controller into their own file and inject them into the index.js file
angular
.module("homeIndex", ["ngRoute", "homeController", "aboutController])
I had left the routing inside that file. FOr some reason I was either using the wrong syntax or doing it wrong.
What you tried don't work because you are trying to load controllers as module dependency.
You can split the files like this and add all of them in your index.html
// index.js
angular
.module("homeIndex", ["ngRoute"]);
//route.js
angular
.module("homeIndex")
.config(config);
function config($routeProvider) {
$routeProvider
.when("/", {
templateUrl: "/ng-templates/homeView.html",
controller: "homeController",
controllerAs: "vm"
})
.when("/about", {
templateUrl: "/ng-templates/aboutView.html",
controller: "aboutController",
controllerAs: "vm"
})
.otherwise({ redirectTo: "/" });
};
// homeController.js
angular
.module("homeIndex")
.controller("homeController", homeController)
function homeController() {
var vm = this;
vm.title = "Home Page";
};
// aboutController.js
angular
.module("homeIndex")
.controller("aboutController", aboutController);
function aboutController() {
var vm = this;
vm.title = "About Us";
};
I'm using $routeProvider for routing in my Angular app. And for 2 routes I'm using same HTML template and same Controller.
when('/products, {
templateUrl: 'views/products.html',
controller: 'ProductListCtrl'
}).
when('/myProducts', {
templateUrl: 'views/products.html',
controller: 'ProductListCtrl'
}).
Only difference in data that I want to show. I.e. for path products I want AJAX request to myserver:8080/products and for for path myProducts I want to load data from AJAX request to myserver:8080/products/my.
For now I i'm using $location service to distinguish the current page (products or myProducts) and load apropriate data.
Is there some more elegant way to do it? For example using resolve method of $routeProvider?
The best way to reuse controller name in today scenario is to use resolve with $routeparams.
You can modify your code as below
when('/products, {
templateUrl: 'views/products.html',
controller: 'ProductListCtrl',
resolve: {
product: function($http) {
return $http.get('/products')
},
needToShowFilter:function($q){
var showfilter = $q.defer();
showfilter.resolve(false);
return showfilter.promise
}
}
}).
when('/myProducts', {
templateUrl: 'views/products.html',
controller: 'ProductListCtrl',
resolve: {
product: function($http) {
return $http.get('/products/my')
},
needToShowFilter:function($q){
var showfilter = $q.defer();
showfilter.resolve(true);
return showfilter.promise
}
}
}).
And then in your controller you can inject the product into the controller code.
try to add $route in your controller, and log
$route.current
to see what you have inside, i think thats the way to get the information
Have an app where admins create ITEMs for users to view. Each ITEM is a doc stored in Mongo.
The item.html view and ItemController.js are consistent for all the ITEMs..
The user is first presented an ITEM_list view..
..where the user can click on an ITEM divBox,
which would reveal the item.html view populated with the specific db content found for the selected ITEM
Is there a way to have angular do something like this in appRoutes.js
angular.module('appRoutes', []).config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider
// start page listing all the ITEMs
.when('/', {
templateUrl: 'views/itemsList.html',
controller: 'ItemsListController'
})
// dynamic pages for each ITEM, once selected ?!
.when('/{{ITEM}}', {
templateUrl: 'views/item.html',
controller: 'ItemController'
});
$locationProvider.html5Mode(true);
}]);
You can use parameters in the route by using a colon before whatever variable name you want.
For example:
.when('/:itemID', {
templateUrl: 'views/item.html',
controller: 'ItemController'
}
Then in your ItemController, you can call that using $routeParams.
.controller('ItemController', ['$scope', '$routeParams',
function($scope, $routeParams) {
$scope.itemID = $routeParams.itemID;
}]);
Here is the link to the Angular docs for some more guidance. http://docs.angularjs.org/tutorial/step_07
You can pass the item id, for example, like so:
.when('/item/:item_id', {
templateUrl: 'views/item.html',
controller: 'ItemController'
})
Then, in your controller, you can inject $routeParams:
.controller('ItemController', function($scope, $routeParams) {
var item_id = $routeParams.item_id;
});
Then, when they select, you set the location to /item/2 or whatever, and you know it is item 2 in your controller, so you can then either fetch that item from the server, or if you have a service with them already loaded you can figure out which one it is.