Trying out a basic example of Angular JS.
Created a index.html file and including the main.html file - controller MainController and using the service - service1.
The data grid population is written in the success callback (onCallComplete) of the service1, which is not called for some reason.
Neither its showing any error.
Where am I going wrong?
Link to my code
change your onCallComplete from
var onCallComplete = function(data) {
$scope.user = data;
service1.getRepos($scope.user).then(onReposComplete, onError);
};
to
function onCallComplete(data) {
console.log(data);
$scope.user = data;
service1.getRepos($scope.user).then(onReposComplete, onError);
}
Here is the working plunker
or move your service1.getUser($scope.username).then(onCallComplete,onError); beneath onCallComplete like given below.
var onCallComplete = function(data) {
$scope.user = data;
service1.getRepos($scope.user).then(onReposComplete, onError);
};
service1.getUser($scope.username).then(onCallComplete,onError);
The Reason is When you define your function as var onCallComplete =function(data) the function definition happens at runtime. but using function onCallComplete(data) the function gets defined while parsing the script.So it would be available at any point during runtime.
Related
I'm trying to use a simple Angular JS app to load data from a JSON file to a website but it does not work.
The JSON file is:
{"a": "a"}
The Angular app is:
var app = angular.module("app", [])
.controller("ctrl", ["ser", function(ser) {
var vm = this;
ser.getInfo().then(function(data) {
vm.data = data;
});
}])
.service("ser", function() {
this.getInfo = function() {
return $.get("models/model.json");
};
});
The HTML is:
<div ng-controller="ctrl as ctrl">
<p>{{ctrl.data.a}}</p>
</div>
I'm not getting any console errors. I think the problem is related to the lexical scoping for the controller due to the asynchronous getInfo().then() call in the controller, I checked vm inside the function and it is being loaded correctly but doesn't seem to change the ctrl object or Angular is not updating when it does.
I'm serving the app locally.
It works sometimes but most times it doesn't. I can get it to work using $scope but I'm trying to figure out why it's not working now.
It appears you are using jQuery for the ajax. If you modify the scope outside of angular context you need to notify angular to run a digest
Change to using angular $http to avoid such issues
var app = angular.module("app", [])
.controller("ctrl", ["ser", function(ser) {
var vm = this;
ser.getInfo().then(function(response) {
vm.data = response.data;
});
}])
.service("ser", ['$http', function($http) {
this.getInfo = function() {
return $http.get("models/model.json");
};
}]);
DEMO
If it works with $scope that means that without it, Angular is not aware that you performed an asynchronous operation.
I think the following line is using jQuery: return $.get("models/model.json");
So even if you get your data from your function getInfo, it isn't synchronized with the view via vm.data = data;
formApp.controller('load', function ($scope, ApiCall, $window, $http) {
$window.onload = function () {
alert("the page loaded and will now call the function");
ApiCall.GetApiCall("signOn", "GetSingleSignOn").success(function (data) {
alert("successful call to singleSignOn, GetSingleSignOn");
var data = $.parseJSON(JSON.parse(data));
$scope.apiGetInfo = data;
alert("successful call to singleSignOn, GetSingleSignOn");
alert(data);
});
};
This code works fine up to the var data- $.parseJson(JSON.parse(data));
I looked at some examples of how to do this in the Controller online and they all looked this way with $.parseJSON(JSON.parse(data)).
It gives me: ReferenceError: $ is not defined
Not sure why as every example I looked at to call an API Controller in Angular showed this way.
You don't need the $.parseJSON. remove it and leave the JSON.parse intact:
var data = JSON.parse(data);
If you want to use JQuery ($) you have to import the script.
UPDATE:
if you want to redirect to an URL you can use $window:
$window.location.href = 'http://www.google.com';
I don't know what it is about injecting factories, but I am having the most difficult time.
I've simulated what I'm attempting to do via this sample plunk http://plnkr.co/edit/I6MJRx?p=preview, which creates a kendo treelist - it works fine.
I have an onChange event in script.js which just writes to the console. That's also working.
My plunk loads the following:
1) Inits the app module, and creates the main controller myCtrl (script.js)
2) Injects widgetLinkingFactory int myCtrl
3) Injects MyService into widgetLinkingFactory
The order in which I load the files in index.html appears to be VERY important.
Again, the above plunk is NOT the real application. It demonstrates how I'm injecting factories and services.
My actual code is giving me grief. I'm having much trouble inject factories/services into other factories.
For example,
when debugging inside function linking() below, I can see neither 'CalculatorService' nor 'MyService' services. However, I can see the 'reportsContext' service.
(function () {
// ******************************
// Factory: 'widgetLinkingFactory'
// ******************************
'use strict';
app.factory('widgetLinkingFactory', ['reportsContext', 'MyService', linking]);
function linking(reportsContext, MyService) {
var service = {
linkCharts: linkCharts
};
return service;
function linkCharts(parId, widgets, parentWidgetData) {
// *** WHEN DEBUGGING HERE, ***
// I CANNOT SEE 'CalculatorService' AND 'MyService'
// HOWEVER I CAN SEE 'reportsContext'
if (parentWidgetData.parentObj === undefined) {
// user clicked on root node of grid/treelist
}
_.each(widgets, function (wid) {
if (wid.dataModelOptions.linkedParentWidget) {
// REFRESH HERE...
}
});
}
}
})();
A snippet of reportsContext'service :
(function () {
'use strict';
var app = angular.module('rage');
app.service('reportsContext', ['$http', reportsContext]);
function reportsContext($http) {
this.encodeRageURL = function (sourceURL) {
var encodedURL = sourceURL.replace(/ /g, "%20");
encodedURL = encodedURL.replace(/</g, "%3C");
encodedURL = encodedURL.replace(/>/g, "%3E");
return encodedURL;
}
// SAVE CHART DATA TO LOCAL CACHE
this.saveChartCategoryAxisToLocalStorage = function (data) {
window.localStorage.setItem("chartCategoryAxis", JSON.stringify(data));
}
}
})();
One other point is that in my main directive code, I can a $broadcast event which calls the WidgetLinking factory :
Notice how I'm passing in the widgetLinkingFactory in scope.$on. Is this a problem ?
// Called from my DataModel factory :
$rootScope.$broadcast('refreshLinkedWidgets', id, widgetLinkingFactory, dataModelOptions);
// Watcher setup in my directive code :
scope.$on('refreshLinkedWidgets', function (event, parentWidgetId, widgetLinkingFactory, dataModelOptions) {
widgetLinkingFactory.linkCharts(parentWidgetId, scope.widgets, dataModelOptions);
});
I am wasting a lot of time with these injections, and it's driving me crazy.
Thanks ahead of time for your assistance.
regards,
Bob
I think you might want to read up on factories/services, but the following will work:
var app = angular.module('rage')
app.factory('hi', [function(){
var service = {};
service.sayHi = function(){return 'hi'}
return service;
}];
app.factory('bye', [function(){
var service = {};
service.sayBye = function(){return 'bye'}
return service;
}];
app.factory('combine', ['hi', 'bye', function(hi, bye){
var service = {};
service.sayHi = hi.sayHi;
service.sayBye = bye.sayBye;
return service;
}];
And in controller...
app.controller('test', ['combine', function(combine){
console.log(combine.sayHi());
console.log(combine.sayBye());
}];
So it would be most helpful if you created a plunk or something where we could fork your code and test a fix. Looking over your services it doen't seem that they are returning anything. I typically set up all of my services using the "factory" method as shown below
var app = angular.module('Bret.ApiM', ['ngRoute', 'angularFileUpload']);
app.factory('Bret.Api', ['$http', function ($http: ng.IHttpService) {
var adminService = new Bret.Api($http);
return adminService;
}]);
As you can see I give it a name and define what services it needs and then I create an object that is my service and return it to be consumed by something else. The above syntax is TypeScript which plays very nice with Angular as that is what the Angular team uses.
I'm trying to pass the videoUrl variable in the showResponse function into my controller. I've been trying to figure out a solution without success. Can anyone guide me in the right direction?
var myApp = angular.module('myApp', []);
myApp.controller('mainCtrl', ['$scope', function($scope){
$scope.videoUrl = videoUrl;
}])
// Helper function to display JavaScript value on HTML page.
function showResponse(response) {
var videoUrl = [];
for (prop in response.items) {
videoUrl[prop] = "https://www.youtube.com/embed/" + response.items[prop].snippet.resourceId.videoId;
}
}
// Called automatically when JavaScript client library is loaded.
function onClientLoad() {
gapi.client.load('youtube', 'v3', onYouTubeApiLoad);
}
// Called automatically when YouTube API interface is loaded
function onYouTubeApiLoad() {
gapi.client.setApiKey('#######');
search();
}
function search() {
// Use the JavaScript client library to create a search.list() API call.
var request = gapi.client.youtube.playlistItems.list({
part: 'snippet',
playlistId: '########'
});
// Send the request to the API server,
// and invoke onSearchRepsonse() with the response.
request.execute(onSearchResponse);
}
// Called automatically with the response of the YouTube API request.
function onSearchResponse(response) {
showResponse(response);
}
It would probably better/easier if you could get this stuff into angular, so that it's all happening within services. That's how data sharing is supposed to happen in angular. But maybe that's challenging due to the nature of onClientLoad. The dirty way to do it is:
Get the controller's scope directly and set it on that scope. Assuming you've got something defined like:
<div ng-controller="mainCtrl"></div>
you can get that controller's scope using jQuery:
function showResponse(response) {
var videoUrl = [];
for (prop in response.items) {
videoUrl[prop] = "https://www.youtube.com/embed/" + response.items[prop].snippet.resourceId.videoId;
}
var scope = $('[ng-controller="mainCtrl"]').scope();
scope.videoUrl = videoUrl;
}
Note that this will cause angular purists to weep and gnash their teeth.
Two Important Notes:
1. My goal is to AVOID using $scope in this case since it's my understanding that impedes the new "controller as" syntax.
2. My problem is likely a variable scope issue and so perhaps just clarifying the proper JS way might solve the problem.
Nevermind the exports, I'm working with browserify in my workflow.
I have this working code:
exports.IntroCtrl = function($scope, $http) {
$scope.introData = [];
$http.get('data/intro.json')
.success(function(res){
$scope.introData = res;
});
};
That ideally I'd like to work as something like this, for the sake of using the "controller as" syntax.
exports.IntroCtrl = function($http) {
this.introData = [];
$http.get('data/intro.json')
.success(function(res){
introData = res;
});
};
The problem is that the $http service seems to be executing before my initial this.introData declaration since I get a variable not defined error.
If tell this.introData = $http.get… then it returns an array of 5 objects that I can't access and intro.json only contains 4.
Thanks for any guidance/help.
First of all create a service for the http call. It is very convenient way to get the callback in the controller and then assign your controller as variables. Here is the factory for you:
Factory
app.factory('getDataService',function ($http) {
return {
getData:function(callback){
$http.get('data/intro.json')
.success(callback)
});
}
}
});
In your controller you get inject the getDataService and bind the data like this:
Controller:
app.controller('testController',['getDataService',function(testDataService){
this.introData = [];
testDataService.getData(function(data){
this.introData = data;
});
}]);
Here you need to bind the introData of the controller function.
You have to remember this variable that reference the controller instance, and use it later in the success callback like this:
exports.IntroCtrl = function($http) {
this.introData = [];
var ctrl = this; // remember 'this', the controller instance, to use in the success callback below
$http.get('data/intro.json')
.success(function (res) {
ctrl.introData = res;
});
};
Hope this helps.