I am calling a REST service from angular and it always calls the factory twice. Here is the factory code.
app.factory('dataFactory', ['$http', function ($http) {
var urlBase = '/api';
var dataFactory = {};
dataFactory.getMyItems = function () {
return $http.get(urlBase + '/MyItems');
};
return dataFactory;
} ]);
It's called from the controller here
app.controller('MyItemsController', ['$scope', 'dataFactory',
function ($scope, dataFactory) {
$scope.myItems;
getItems();
function getItems() {
dataFactory.getMyItems()
.success(function (itemsData) {
$scope.myItems = itemsData;
})
.error(function (error) {
$scope.status = 'Unable to load items data: ' + error.message;
});
}
}
]);
I had the same problem as yours where the controller in general was called twice; hence, the factory will be called twice.
But after looking at this solution:
Combating AngularJS executing controller twice
Step 1:
Make sure you are adding the service and controller in your (main layout view) only once.
Example:
index.html
<script src="../MyItemsController.js"></script>
<script src="../MyItemsService.js"></script>
If the problem still persists after doing step 1 go to step 2
Step 2:
There are two ways to do it:-
1. Either keep the controller in your view (ng-controller), and remove it from your config route like this:
route config (usually, app.js):
app.config(['$routeProvider', function($routeProvider){
$routeProvider.when('/',
{
templateUrl: 'pages/home.html'
//Remove controller from here
});
}]);
home.html
<!-- Add the ng-controller in your view -->
<div ng-controller="MyItemsController">
<!-- Your stuff -->
</div>
2. Or keep the controller in your config route, and remove ng-controller
from view like this:
route config (usually, app.js):
app.config(['$routeProvider', function($routeProvider){
$routeProvider.when('/',
{
templateUrl: 'pages/home.html',
controller: 'MyItemsController' //Add the controller here
});
}]);
home.html
<!-- Remove the ng-controller in your view -->
<div>
<!-- Your stuff -->
</div>
Note: The above solution works with ui router as well.
Related
I have three partial pages in my application and I am using ng-View directive to route to the pages. Also I have separate controller for pages. Now in two of the pages I am making http calls to get / post data, where I am using service to call REST APIs.
Now the problem I am facing every time I am routed to a page, it gets loaded again (executing the function which is making http calls).
In a post like this I saw it is said that this is a default behavior but if so, how can I prevent this to happen. The link I saw is:
The link
Now how can I prevent that to happen, I really do not need to load pages after it is loaded for the first time, when routed.
The code snippets are as follows..
In index.html
To call page link:
...
<md-button class="md-primary" ng-href="#/">Report</md-button>
<md-button class="md-primary" ng-href="#about">About</md-button>
...
<div ng-view></div>
....
In partial1.html, I am not assigning any controller.
In App.js file, setting the route config...
angular
.module('webApp')
.config(function ($routeProvider) {
$routeProvider
.when('/', {
//url: "/report",
templateUrl: 'pages/report.html',
controller: 'ReportController'
})
.when('/about', {
templateUrl: 'pages/about.html',
controller: 'aboutController'
})
.....
In controller ....
angular
.module('webApp')
.controller('ReportController',
function ($scope, $log, $mdDialog, webAppService) {
var GetReportsFromDB = function () {
webAppService.GetReports().success(function (rptData) {
var dd = JSON.parse(rptData);
rptvm.reports = dd;
}).error(function (response) {
console.log(response);
}).then(function () {
});
};
GetReportsFromDB();
...
In Service ...
angular
.module('webApp')
.service('webAppService', ['$http', function ($http) {
var svc = {};
svc.GetReports = function () {
console.log('loading...');
return $http({
method: 'GET',
url: 'http://somedomain/api/mycontroller/myaction',
});
};
......
I am very new at AngularJS. Any help will be appreciated.
Thanks in advance,
Arpan
Hi iam using Angular with Require.
Require is managing my dependency sequence. Using lazy loading for loading controller and i was able to load my first home controller but when i wanted to navigate to dashboard controller then iam getting error dashboard controller is not found. hereis code
main.html
<body ng-app >
<div id="ViewPort" ng-view> </div>
</body>
shell.js
define(['mngRoute', 'mngSanitize'], function (ngRoute, ngSantize) {
var CMSapp = angular.module('CMS', ['ngRoute', 'ngSanitize']);
CMSapp.config(function ($routeProvider, $httpProvider) {
console.log($httpProvider);
$routeProvider
// route for the home page
.when('/', { templateUrl: 'App/Partials/home.html', resolve: loader(['Home']) })
.when('/Dashboard', { templateUrl: 'App/Partials/Dashboard.html', resolve: loader(['Dashboard']) })
});
CMSapp.run(function () {
console.log('shell loaded');
console.log(CMSapp);
});
return CMSapp;
Home Controller.js
define(function () {
angular.module('CMS').controller('HomeController', ["$scope", "$http", 'MainService', function ($scope, $http, mainService) {
$scope.message = 'Homess';
$scope.InitializeController = function ()
{
console.log(mainService);
mainService.initializeApplication($scope.initializeApplicationComplete, $scope.initializeApplicationError);
}
$scope.initializeApplicationComplete = function (response) {
console.log('in default initializeApplicationComplete');
}
$scope.initializeApplicationError = function (response) {
console.log('in default intialize error');
}
}]);
});
Home.html
<div data-ng-controller="HomeController" ng-init="InitializeController()">
<span>{{message}}</span>
Dashboardcontroller and dashboard.html are same only difference is the name
define(function () {
angular.module('CMS').controller('DashboardController', ["$scope", "$http", 'MainService', function ($scope, $http, mainService) {
$scope.message = 'Dashboard';
$scope.InitializeController = function ()
{
console.log(mainService);
}
}]);
});
Dasboard html
<div data-ng-controller="DashboardController" ng-init="InitializeController()">
<span>{{message}}</span>
i was able to load home and able to bind with model, but this not in dashboard when i entered localhost:8999/Main.html#/Dashboard in url it gives error.
See the chrome console Full console
Angular, Route, Dasboardcontroller.js homecontroller.js shell.js are loaded successfuly no error in console only error is Dasboard controller is not a function, got defined
When you use ng-app, Angular will search for a module called app. If you want to specify a custom module, you need to tell it: ng-app="CMS"
I hope this works! :)
<body ng-app >
should be
<body ng-app="CMS">
because in your code you declare your module as so.
angular.module('CMS'
Chrome console image console2
You can see my app is loaded bootstrapped and controllers are registered as well
Here i will add the product data from response of http for myctrl then when i click on checkout i have to bind all this information and send it to another jsp page in that page i have to get the response data.How can i achieve it by using angularjs. please help me out
<div ng-app="MyApp" ng-controller="MyCtrl">
<div ng-repeat="x in names">
<div>Product Name : {{x.itemname}}</div>
<div>Qty : {{x.itemQty}}</div>
<div>Price : {{x.itemQty}}</div>
<div>Total : {{x.itemQty}}</div>
</div>
<div><button ng-click="checkOut()" >CheckOut</button></div>
</div>
<script>
angular.module("MyApp",[])
.controller("MyCtrl", ['$scope', '$http', function($scope, $http) {
$http.get('responseData.html').success(function(response) {
$scope.names= response;
});
}]);
</script>
Whenever you want to persist the any object/value on client side, I'd suggest you to don't redirect the user to other page.
Instead do create a SPA, add route based view to your application. For implementing such a powerful SAP you could use angular-route API designed by angular team OR you could also use ui.router which is developed by angular-ui team. Suppose you choose angular-route here then, show different view on different routes, you need to configure you route in angular config phase using $routeProvider & then load view and controller for partial view. In your case it would be confirmation submit page on click of button.
You could have one wrapper div on your ng-view directive and then give mainCtrl controller to it. That will act as a sharing component amongest your various views.
HTML
Controller
var app = angular.module('app', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/view1', {
templateUrl: 'view1.html',
controller: 'CustomerDetailsController'
})
.when('/view2', {
templateUrl: 'view2.html',
controller: 'form2Ctrl'
})
.otherwise({
redirectTo: '/view1'
});
});
app.controller('mainCtrl', function($scope) {
$scope.form = {}; //this is global and thats why it can be available on any view
});
app.controller('CustomerDetailsController', function($scope,$location) {
$scope.submit = function(){
if($scope.form1.$valid)
$location.path('/view2');
};
});
app.controller('form2Ctrl', function($scope,$location) {
//this controller contain the data which will you get from
});
Preferable approach for sharing a data would be using singleton service/factory in your application.
HTML
<div class="forms">
<ng-view></ng-view>
</div>
app.service('sharedData', function() {
var sharedData = this;
sharedData.myData = {};
});
app.controller('CustomerDetailsController', function($scope,$location, sharedData) {
$scope.submit = function(){
sharedData.myData.formData = $scope.form1Data; //form1Data will have form1Data
if($scope.form1.$valid)
$location.path('/view2');
};
});
app.controller('form2Ctrl', function($scope,$location, sharedData) {
console.log(sharedData); //this will have the data shared from the CustomerDetailsController
});
For more info Refer this SO Question, Thanks.
I try to load route only after promises are resolved
var app = angular.module("thethaoso", ["ngRoute"]);
app.config(['$routeProvider', '$locationProvider', function ($routeProvider) {
$routeProvider
.when('/', {
resolve: {
message: function (repoService) {
return repoService.getMsg();
}
}
});
}]);
app.factory('repoService', function ($http) {
return {
getMsg: function () {
return "hihihi";
}
};
});
app.controller('teamLoadCtrl', function ($scope,message) {
$scope.message= message;
});
View:
<div ng-app='thethaoso' ng-controller='teamLoadCtrl'>
{{message}}
</div>
Always get the error Error: [$injector:unpr]http://errors.angularjs.org/1.3.7/$injector/unpr?p0=messageProvider%20%3C-%20message%20%3C-%20teamLoadCtrl
full code at http://jsfiddle.net/c0y38yp0/5/
Am I missing something ?
Thanks all.
The problem is that you have not specified a template and a controller to resolve the message object to. If you used the following syntax, it will work.
.when("/", {
templateUrl: "yourView.html",
controller: "yourController",
resolve: {
message: function(yourService){
return yourService.get();
}
}
Here is a working jsfiddle: http://jsfiddle.net/c0y38yp0/10/
You can also resolve the promise manually in your controller like so:
repoService.getMsg()
.then(function (msg) {
$scope.message = msg;
}
When the promise is resolved onto the scope as I did above, the ui will update. You can show a loading bar and use ng-hide to make the pages feel fluent while the loading occurs.
When you resolve, service have to return promise not value.
Here is example service
app.factory('repoService', function ($http, $q) {
var user = {};
var q = $q.defer();
$http.get('https://api.github.com/users/Serhioromano')
.success(function(json){
user = json;
q.resolve();
}).error(function(){
q.reject();
});
return {
promise: function() {
return q.promise;
},
get: function() {
return user;
}
};
});
The point here is that you return promise only. You handle how you save result. And then you can use this result like in get(). You know that by the time you call get() the user variable already set because promise was resolve.
Now in router.
app.controller('MainCtrl', function($scope, repoService) {
$scope.user = repoService.get();
});
app.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: '/view.html',
controller: 'MainCtrl',
resolve: {
message: function (repoService) {
return repoService.promise();
}
}
})
.otherwise({ redirectTo: '/' });
});
You return promise by repoService.promise()
In controller repoService.get() is triggered only after that promise resolved.
So you get your data.
Another thing in your code, you used ng-controller. But that thing is not binded to router and thus it avoid if it is resolved or not. You have to delete ng-controller and use controller router controller: 'MainCtrl',.
This affect your HTML
<body ng-app="myapp">
<ng-view></ng-view>
<script type="text/ng-template" id="/view.html">
<p>Hello {{user.name}}!</p>
</script>
<body>
You have to use <ng-view> to include subtemplate there and then in sub template you can use scope of the controller.
See plunker.
There are a few things wrong with the code you posted, in contrast to the code you are attempting to draw inspiration from.
When you resolve a route with the $routeProvider, the results are applied against an element <ng-view></ngview>, not a base element <div> as you have specified. Without the <ng-view> element, there is no way for the $routeProvider to bind the correct controller to the correct html fragment. Using ng-controller instantiates a controller instance when the dom element is rendered, and does not allow passing parameters to the controller as you have tried. Thus your resolution error due to an unknown message object. Effectively, message is not available outside the $routeProvider instance.
I have created a simple Angular JS $routeProvider resolve test application. It gives the following error:
Error: Unknown provider: dataProvider <- data
I would appreciate it if someone could identify where I have gone wrong.
index.html
<!DOCTYPE html>
<html ng-app="ResolveTest">
<head>
<title>Resolve Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js"> </script>
<script src="ResolveTest.js"></script>
</head>
<body ng-controller="ResolveCtrl">
<div ng-view></div>
</body>
</html>
ResolveTest.js
var rt = angular.module("ResolveTest",[]);
rt.config(["$routeProvider",function($routeProvider)
{
$routeProvider.when("/",{
templateUrl: "rt.html",
controller: "ResolveCtrl",
resolve: {
data: ["$q","$timeout",function($q,$timeout)
{
var deferred = $q.defer();
$timeout(function()
{
deferred.resolve("my data value");
},2000);
return deferred.promise;
}]
}
});
}]);
rt.controller("ResolveCtrl",["$scope","data",function($scope,data)
{
console.log("data : " + data);
$scope.data = data;
}]);
rt.html
<span>{{data}}</span>
The problem is that you have ng-controller="ResolveCtrl" on your body tag in index.html when also in your $routeProvider you specify the same controller for rt.html. Take out the controller definition from your body tag and just let the $routeProvider take care of it. It works great after that.
According to the angularjs documentation for $routeprovider the resolve object is a map from key (dependency name) to factory function or name of an existing service. Try this instead:
var myFactory = function($q, $timeout) { ... };
myFactory.$inject = ['$q', '$timeout'];
$routeProvider.when("/",{
templateUrl: "rt.html",
controller: "ResolveCtrl",
resolve: {
data: myFactory
}
});
By adding data to the definition of the controller your telling angular that you expect to inject a service or factory here yet you don't have a data service or factory thus the error. To use the data variable you have all you need from the $scope.data line. So to fix this you need to remove the data injection from your controller call.
var rt = angular.module("ResolveTest",[]);
rt.config(["$routeProvider",function($routeProvider)
{
$routeProvider.when("/",{
templateUrl: "rt.html",
controller: "ResolveCtrl",
resolve: {
data: ["$q","$timeout",function($q,$timeout)
{
var deferred = $q.defer();
$timeout(function()
{
deferred.resolve("my data value");
},2000);
return deferred.promise;
}]
}
});
}]);
rt.controller("ResolveCtrl",["$scope", function($scope)
{
$scope.data = "";
}]);
If you want to have a data provider add a factory something like
rt.factory('data', ['$http', function($http){
return {
// Functions to get data here
}
}]);
Then in your controller call the appropriate function from this factory.
Also as the others have pointed out you don't need the controller both in your route and in an ng-controller (this will nest your controller in your controller if you inspect the scopes).
If you must use resolve you still need a factory as resolve will just point to the proper factory which needs to be declared separately.