I found many similar questions but I couldn't apply the solutions to my problem.
So in my angular app I am drawing nvd3 charts.
I am doing a get request in the service and I can see from the network in my browser that I am ALWAYS getting the chart data as I am supposed to.
The problem is that, when I am running grunt serve to start my angular app, I am still getting the data through the api, but for some reason they are not shown.
That just happens only when I run grunt serve. However, if I hit refresh, after running grunt serve, the data are shown correctly.
Thanks in advance for any help.
this is what I am trying to do:
'use strict';
angular.module('myApp')
.service('mainService', function($http) {
this.getData = function() {
return $http({
method: 'GET',
url: '/rest/api/config',
});
}
})
.controller('MainCtrl', function($scope, $http, mainService) {
var name = 'main';
var model;
mainService.getData().then(function(d) {
model = d.data;
$scope.modelling();
});
$scope.modelling = function() {
if(!model) {
console.log("no model");
// set default model for demo purposes
model = {
title: "about",
structure: "12/4-4-4",
};
}
console.log(model);
$scope.name = name;
$scope.model = model;
$scope.collapsible = true;
}
});
Try something like this. Initially, in your example, $scope.model is going to be undefined.
.controller('MainCtrl', function($scope, $http, mainService) {
var name = 'main';
mainService.getData().then(function(d) {
$scope.modelling(d.data);
});
$scope.modelling = function(data) {
//do something with data here, or set
$scope.model = data;
}
$scope.name = name;
$scope.collapsible = true;
}
});
That might work, depends on how you set up the nvd3 charts.
Related
I was recomended to use Angular services in order to centralize many repetative functions that were store in my controller, so I am rewriting my code using services now.
It seemed simple at first but cant seem to find a good structure to fetch my ajax data (only once), then store it in my service for my controller to reuse the cached data when ever it needs it. At the moment I keep getting errors saying: TypeError: Cannot read property 'sayHello' of undefined.
I believe this is because theres is a delay to fetch my ajax data via my service before the controller loads. Im not quite certain how I can optimize this. Would anyone have a better stucture to this?
Service:
app.service('MyService', function ($http) {
this.sayHello = function () {
var deferred = $q.defer();
$http({
method: 'GET',
url: 'AJAX PATH',
headers: { "Accept": "application/json;odata=verbose;charset=utf-8"}
}).then(function(data){
var configurations = data;
var configurations.data_result_1 = configurations.data_result_1.split("\r\n");
var configurations.data_result_2 = configurations.data_result_2.split("\r\n");
deferred.resolve(configurations);
}
return deferred.promise;
};
this.sayHello(); //Run the function upon page laod.
});
Controller:
app.controller('AppController', function (MyService, $scope) {
$scope.configurations = null;
$scope.configurations = function() { MyService.sayHello() };
});
I recommend you to use another way to declare the service:
app.factory("MyService", function($http){
var configurations = {};
$http({
method: 'GET',
url: 'AJAX PATH',
headers: { "Accept": "application/json;odata=verbose;charset=utf-8"}
}).then(function(data){
configurations = data;
configurations.data_result_1 = configurations.data_result_1.split("\r\n");
configurations.data_result_2 = configurations.data_result_2.split("\r\n");
});
return {
getConfigurations: function(){
return configurations;
}
}
In your controller you can use a $watch, then when the configurations objects changes you take the information:
.controller("YourCtrl", function($scope,MyService){
var vm = this;
vm.configurations = {};
$scope.$watchCollection(function () { return MyService.getConfigurations()},function(newValue){
vm.configurations = newValue;
});
Totally agree with Bri4n about store configuration in the factory. Not agree about the controller because you said you don't want to watch, but only load data once.
But you $http already return a promise so as Brian said this is nice (just $q is useless here so you can delete it from injection). And I just wrapped http call in function, and the exposed function just check if configurations are already loaded. If yes, just return configurations else load it and then return it.
app.factory("MyService", function($http,$q){
var configurations = {};
function loadConfig(){
$http({
method: 'GET',
url: 'AJAX PATH',
headers: { "Accept": "application/json;odata=verbose;charset=utf-8"}
}).then(function(data){
configurations = data;
configurations.data_result_1 = configurations.data_result_1.split("\r\n");
configurations.data_result_2 = configurations.data_result_2.split("\r\n");
});
}
return {
getConfigurations: function(){
If( !!configurations ){
return configurations;
}
//Else loadConfig.then return configurations
}
}
In your controller you can just get config without need to know if it is already loaded.
.controller("YourCtrl", function(MyService){
var vm = this;
// If configurations already loaded return config, else load configurations and return configurations.
vm.configurations = MyService.getConfigurations();
I write on my phone so my code is not perfect I can't write properly.
OK, on second thought, it looks like you are not using the dependency array notation properly. Change your code to:
app.service('MyService', ['$http', function ($http) {
// do your stuff here
}]);
and for the controller:
app.controller('AppController', ['MyService', '$scope', function(MyService, $scope) {
// do your stuff here
}]);
I'm working on a mobile app using AngularJS as a framework, currently I have a structure similar to this:
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl : 'pages/home.html',
controller : 'homeCtrl'
})
.when('/one', {
templateUrl : 'pages/one.html',
controller : 'oneCtrl'
})
.when('/two', {
templateUrl : 'pages/two.html',
controller : 'twoCtrl'
});
}]);
app.controller('homeCtrl', ['$scope', function($scope) {
}]);
app.controller('oneCtrl', ['$scope', function($scope) {
}]);
app.controller('twoCtrl', ['$scope', function($scope) {
}]);
And then I'm displaying the content with an ng-view:
<div class="ng-view></div>
Things are working well but I need to load data from a JSON file to populate all the content of the app. What I want is to make and an AJAX call only once and then pass the data through all my different controllers. In my first attempt, I thought to create a Service with an $http.get() inside of it and include that in every controller, but it does not work because it makes a different ajax request everytime I inject and use the service. Since I'm new using angular I'm wondering what is the best way or the more "angular way" to achieve this without messing it up.
Edit: I'm adding the code of the service, which is just a simple $http.get request:
app.service('Data', ['$http', function($http) {
this.get = function() {
$http.get('data.json')
.success(function(result) {
return result;
})
}
});
Initialize the promise once, and return a reference to it:
No need to initialize another promise. $http returns one.
Just tack a .then() call on your promise to modify the result
angular.module('app', [])
.service('service', function($http){
this.promise = null;
function makeRequest() {
return $http.get('http://jsonplaceholder.typicode.com/posts/1')
.then(function(resp){
return resp.data;
});
}
this.getPromise = function(update){
if (update || !this.promise) {
this.promise = makeRequest();
}
return this.promise;
}
})
Codepen example
Edit: you may consider using $http cache instead. It can achieve the same results. From the docs:
If multiple identical requests are made using the same cache, which is not yet populated, one request will be made to the server and remaining requests will return the same response.
Try this to get JSON Data from a GET Link:
(function (app) {
'use strict';
app.factory('myService', MyService);
MyService.$inject = ['$q', '$http'];
function MyService($q, $http) {
var data;
var service = {
getData: getData
};
return service;
//////////////////////////////////////
function getData(refresh) {
if (refresh || !data) {
return $http.get('your_source').then(function(data){
this.data = data;
return data;
})
}
else {
var deferrer = $q.defer();
deferrer.resolve(data);
return deferrer.promise;
}
}
}
}(angular.module('app')));
Now you can add this dependency in your controller file and use:
myService.getData().then(function(data){
//use data here
}, function(err){
//Handle error here
});
I have been trying out some AngularJS tutorials and dabbling around trying to create a simple website.
I have a directive that creates a side navigation bar and populates the list of items from some json data stored on my server. The name list is populated without an issue.
The problem is that I need to share that name between several controllers, but I am not having any luck doing so.
My app.js contains:
var app = angular.module("Myapp", ['ui.bootstrap']);
app.service('nameService', function() {
var name = "";
this.setName = function(name) {
this.name = name;
}
this.getName = function() {
return name;
}
});
app.directive("sideBar", ['$http', function($http) {
return {
restrict: 'E',
templateUrl: "views/sidebar.html",
controller: function($scope) {
$scope.updateName = function(name) {
alert(name);
};
$http.get('../data/names.json').
success(function(data, status, headers, config) {
$scope.names = data;
}).error(function(data, status, headers, config) { });
}
};
}]);
From what I've read you should just be able to inject the service as a dependency as follows:
app.directive("sideBar", ['$http', 'nameService', function($http, nameService) {
Then I should be able to update the value like so:
$scope.updateName = function(name) {
nameService.setName(name);
};
However, when I try to inject the dependency it breaks the entire directive and the sidebar will no longer load.
I have been pulling my hair out trying to figure out why it breaks without much luck. Is there something I am missing? Or am I going about this the complete wrong way?
I'm working through this tutorial on creating a single-page MEAN stack todo app. I'm on this step, specifically. The tutorial covers modularization of code, and while I was able to separate my backend code (Express, Mongo, etc.) into modules successfully, when I separate my angular.js code, the todo app ceases to function. The specific error which is thrown to the console is "Uncaught Error: [$injector:modulerr]." The specific error is "nomod" (i.e. the module "simpleTodo" is failing to load.) I'd appreciate any help.
Code as one file (core.js):
var simpleTodo = angular.module('simpleTodo', []);
simpleTodo.controller('mainController', ['$scope', '$http', function($scope, $http) {
$scope.formData = {};
$http.get('/api/todos')
.success(function(data) {
$scope.todos = data;
})
.error(function(data) {
console.log('Error: ' + data);
});
$scope.createTodo = function() {
$http.post('/api/todos', $scope.formData)
.success(function(data) {
$scope.formData = {};
$scope.todos = data;
})
.error(function(data) {
console.log('Error: ' + data);
});
};
$scope.deleteTodo = function(id) {
$http.delete('/api/todos/' + id)
.success(function(data) {
$scope.todos = data;
})
.error(function(data) {
console.log('Error: ' + data);
});
};
}]);
Code in modules:
New core.js:
var simpleTodo = angular.module('simpleTodo',['todoController', 'todoService']);
Create/Delete Todo Service (todos.js):
angular.module('todoService', [])
.factory('Todos', ['$http', function($http) {
return {
get: function() {
return $http.get('/api/todos');
},
create: function(todoData) {
return $http.post('/api/todos', todoData);
},
delete: function(id) {
return $http.delete('/api/todos/' + id);
}
}
}]);
Controller file (main.js)
angular.module('todoController', [])
.controller('mainController', ['$scope', '$http', 'Todos', function($scope, $http, Todos) {
$scope.formData = {};
Todos.get()
.success(function(data) {
$scope.todos = data;
});
$scope.createTodo = function() {
if ($scope.formData !== null) {
Todos.create($scope.formData)
.success(function(data) {
$scope.formData = {};
$scope.todos = data;
});
}
};
$scope.deleteTodo = function(id) {
Todos.delete(id)
.success(function(data) {
$scope.todos = data;
});
};
}]);
Order of script loading on index.html:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.min.js"></script>
<script src="js/controllers/main.js"></script>
<script src="js/services/todos.js"</script>
<script src="js/core.js"></script>
Thanks!
New info: After following floribon's advice, I get the same error, except instead of "simpleTodo" failing to load, it is "todoController" that cannot be loaded. I appreciate his advice but it still isn't working. :( Here's a github repo with his changes implemented, if you want to see: https://github.com/LeungEnterprises/simpleTodo
Since your controller needs to resolve the Todos dependency, you need to add the service todoService it to its module dependencies:
angular.module('todoController', ['todoService'])
Also, you will need to load the todos.js file before the main.js one (sicne it requires the former)
I perused my files and after extensive experimentation I deduced that the problem was being caused in the HTML file. The problem was an unclosed script tag.
However, I do appreciate everyone's help, especially #floribon!
I'm trying to import JSON data into an angularJS application. I split my app into a controller and the import-service, but both in different files. I'm also using bower, grunt and yeoman (that's due to work, I'm not quite used to these, maybe there's also a problem.)
The strange behavior is:
I wanted to retrieve the JSON data with a $http.get() and resolve it - all within a service, so that I can hand out the data object from there to the main controller and won't have to resolve it there.
Strangely, I didn't get any data, it was empty or not readable. Then I handed out the promise which I the $http.get() mehtod gives back and resolved it in the controller. That's not what I wanted, but now it works.... but why?
I guess it's a schmall misstake somehwere but neither me nor my team members can find one. Strangely, doing a little test-app without grunt, yeoman and bower it worked.
I'd appreciate every hint or idea...
Jana
Here's my code from the NOT working version, first the main module with controller:
/** Main module of the application. */
(function () {
'use strict;'
angular.module('angularRegelwerkApp', [])
.controller('RegelwerkCtrl', function ($scope, CategoryFactory) {
$scope.categories = CategoryFactory.getCategories();
$scope.subcategories = CategoryFactory.getSubCategories();
}
);
})();
Service-part:
(function () {
'use strict';
var app = angular.module('angularRegelwerkApp')
.service('CategoryFactory',
function ($http) {
var categories = [];
var subcategories = [];
$http.get("../mockdata/categories.json").then(function (response) {
categories = response.data;
})
$http.get('../mockdata/subcategories.json').then(function (response) {
subcategories = response.data;
})
return {
getCategories: function(){
return categories;
},
getSubCategories: function(){
return subcategories;
}
}
}
);
})();
Here's my code from the WORKING version, first the main module with controller:
/** Main module of the application. */
(function() {
'use strict;'
angular.module('angularRegelwerkApp', [])
.controller('RegelwerkCtrl', function ($scope, CategoryFactory) {
$scope.categories = [];
$scope.subcategories = [];
CategoryFactory.getCategories().then(function(response) {
$scope.categories = response.data;
});
CategoryFactory.getSubCategories().then(function(response) {
$scope.subcategories = response.data;
});
}
);
}
)();
Service-part:
(function () {
'use strict';
var app = angular.module('angularRegelwerkApp')
.service('CategoryFactory',
function ($http, $q) {
var categoryURL = "../mockdata/categories.json";
var subcategoryURL = '../mockdata/subcategories.json';
function getSubCategories() {
return $http.get(subcategoryURL);
}
function getCategories() {
return $http.get(categoryURL);
}
return {
getCategories: getCategories,
getSubCategories: getSubCategories
}
}
);
})();
This is destroying your reference, so loop over the data from the server and push it into the variables you need:
$http.get("../mockdata/categories.json").then(function (response) {
for(var x = 0; x < response.data.length; x++){
categories.push(response.data[x]);
}
});
$http call is by default asynchronous.
So in your first version, when you write like $scope.categories = CategoryFactory.getCategories();
you get empty categories, since by the time you access categories, it may not have been loaded with response data.
your app flows like this -
you load the controller
you call the service
service calls $http
you try to access categories (but data will not be available until response is returned from server)
$http.then loads data to $scope.categories
You are storing your data in Angular primitives and these don't update. instead store all your data in an object and it shoudl work (you'll also need to update controller)
(function () {
'use strict';
var app = angular.module('angularRegelwerkApp')
.service('CategoryFactory',
function ($http) {
var data = {};
$http.get("../mockdata/categories.json").then(function (response) {
data.categories = response.data;
})
$http.get('../mockdata/subcategories.json').then(function (response) {
data.subcategories = response.data;
})
return {
getCategories: function(){
return data.categories;
},
getSubCategories: function(){
return data.subcategories;
}
}
}
);
})();