I've an working Endpoint, tested successfully with API-Explorer local and on AppEngine. Now I try to develop an AngularJS-Client. I read a lot of stuff the last week, but it doesn't work. My Controller looks like that.
'use strict';
const WEB_CLIENT_ID = "<...>.apps.googleusercontent.com";
const EMAIL_SCOPE = "https://www.googleapis.com/auth/userinfo.email";
function init() {
window.init();
}
angular.module('stakeholder1', [])
.controller('StakeholderController', ['$scope', '$window',
function StakeholderController($scope, $window) {
$window.init= function() {
$scope.$apply($scope.load_oauth_lib);
$scope.$apply($scope.load_stakeholder_lib)
};
$scope.load_oauth_lib = function() {
gapi.client.load('oauth2', 'v2', null);
gapi.auth.authorize({client_id: WEB_CLIENT_ID,
scope: EMAIL_SCOPE, immediate: false},
null);
};
$scope.is_backend_ready = false;
$scope.load_stakeholder_lib = function() {
gapi.client.load('stakeholderendpoint', 'v1',
function(){
$scope.is_backend_ready = true;
}, 'https://my-stakeholders.appspot.com/_ah/api');
};
$scope.saveStakeholder= function() {
stakeholder = {
"name" : $scope.name
};
gapi.
client.stakeholderendpoint.saveStakeholder(stakeholder).execute();
}
}]);
My mark-up looks like that. If I remove the ng-show-Directive and post a name, I get an error "angular.js:13236 ReferenceError: stakeholder is not defined". So I think the API is not loaded.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html ng-app="stakeholder1">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>MyStakeholders</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="../app/controllers/stakeholder1.js"></script>
<script src="https://apis.google.com/js/client.js?onload=init"></script>
</head>
<body>
<h1>MyStakeholders</h1>
<div ng-controller="StakeholderController" class="container" ng-show="is_backend_ready">
<form ng-submit="saveStakeholder()">
<input type="text" ng-model="name" required><br>
<input type="submit" class="btn" value="Post">
</form>
</div>
</body>
</html>
I'm using Eclipse with GPE. In my WEB-INF-directory there is a generated file stakeholderendpoint-v1.api. Should this file being loaded with gapi.client.load?
I would be glad about some hints or advice how I can debug the load process.
Yes, the stakeholderendpoint should be loaded with gapi.client.load() into the gapi before it is used like gapi.client.stakeholderendpoint.
That file in the WEB-INF directory is important but you can ignore it. The function gapi.client.load() will handle everything behind the scenes.
In your code, the flag $scope.is_backend_ready is indicating if the endpoint is loaded and ready for use. You can protect your UI against errors with this flag. But I recommend to store it in the $rootScope for future use in other controllers. Or even better is to create a service, which loads all the endpoints and store the state of is_backend_ready. Then you can decide to show some progress bar during the loading the endpoints, until the is_backend_ready is true.
Or you can use angular-gapi library.
Related
I have a select that calls a controller in a directive, that in turn calls a function from a service when the user selects a value in the dropdown list. For some reason I'm getting this error:
TypeError: myService.getMessage is not a function
So I created a plunker to pull out the basic functionality and I was able to duplicate the error using a controller to call a basic service, but I'm still not solving it yet.
Here is the code:
HTML Code:
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.2.x" src="https://code.angularjs.org/1.2.22/angular.js" data-semver="1.2.22"></script>
<script src="script.js"></script>
</head>
<body ng-controller="MainCtrl">
<select ng-options="option for option in listOfOptions"
ng-model="selectedItem"
ng-change="selectedItemChanged()">
</select>
<p>This is the selected Item from the model: <b>{{selectedItem}}</b></p>
<p>This is the result of the ng-change function: <b>{{calculatedValue}}</b></p>
</body>
Script Code:
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope, myService) {
$scope.listOfOptions = ['One', 'Two', 'Three'];
$scope.selectedItemChanged = function(){
$scope.calculatedValue = 'You selected number ' + $scope.selectedItem;
//Call the service.
myService.getMessage();
}
});
app.service('myService', function(){
function getMessage(){
alert("You are in myService!");
}
});
I've seen lots of different, much more complicated code for this type of error, but I'm not understanding what is causing this? Any ideas as to the proper way to do this?
What I'm trying to do is to use a function like myService.mySearch(param1) from a controller or directive.
wrong service code, should be:
app.service('myService', function() {
this.getMessage = function() {
alert("You are in myService!");
}
});
.service() is a function which takes a name and a function that defines the service.It acts as a constructor function.We can inject and use that particular service in other components : controllers, directives and filters.
Correct Syntax :
app.service('myService', function(){
this.getMessage = function(){
alert("You are in myService!");
}
});
Main thing is that service is a constructor function. Hence, we can work with this keyword. In background, this code calls Object.create() with the service constructor function, when it gets instantiated.
In addition to Fetra R 's answer,
Factory is mostly preferable in all cases. It can be used when you have constructor function which needs to be instantiated in different controllers. Service is a kind of Singleton Object. The Object return from Service will be same for all controller.
So as it is like a singleton object, you have to declare it as The Fetra R's Answer, or You may write a factory.
app.factory('myService', function() {
return {
getMessage: function() {
alert("You are in myService!");
}
}
});
and use it in the same manner.
I am new to Angular Js and i have just done basic tags of angularjs,controller and when i started directive part i understood the concept but was unable to fetch data input written in template which is one of the directive property..Please guide me so that i can take one step further in AngularJS.
Thanks in Advance!!
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body>
<div ng-app="appname" directive-name></div>
<script>
var app = angular.module("appname",[]);
app.directive("directiveName",function()
{
return
{
template : "Hi i am template"
};
});
</script>
</body>
</html>
Nothing wrong with your logic or Angular, it's because of JavaScript automatic semicolon insertion. Lines that do not end with a semicolon, but could be the end of a statement are automatically terminated. So, your return statement -
app.directive("directiveName",function()
{
return //automatic semicolon insertion here
{
template : "Hi i am template"
};
});
Should be indeed -
app.directive("directiveName",function()
{
return{
template : "Hi i am template"
};
});
Your close:
<!doctype html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body ng-app="appname" ng-controller="MyController">
<h1>{{Header}}</h1>
<my-template></my-template>
<script>
var app = angular.module("appname",[]);
app.controller("MyController", function ($scope){
$scope.Header = "My Directive";
});
app.directive("myTemplate",function() {
return {
template : "<span>Hi i am template</span>",
restrict: 'E',
};
});
</script>
</body>
</html>
I've tested the above code and will render your directive.
everything is allright, except the linebreak after the return.
return {
template : "Hi i am template"
};
There are many problems:
1. You should use https for cdn
2. You have to put var app = angular.module("appname",[]); before the ng-app tag
the return should be
return { //the brace should be after return
template : "Hi i am template"
};
because in modern browsers semicolons are not mandatory(they are added automatically), so return means returns nothing.
finally:
<script>
var app = angular.module("appname",[]);
app.directive("directiveName",function()
{
return{
template : "Hi i am template"
};
});
</script>
Working on a reporting application where reports are generated (in HTML) from a BIRT Report Engine object. The report data comes as a JSON string is recieved from XHR. The JSON string contains a combination of HTML and javascript (a function call, specifically). Once received, the report data is stuffed into a for display in the view. The view is put together using AngularJS.
I did some research and found that binding the HTML/javascript to the view in Angular requires the use of $compile. Using that as a basis, i put together some code that will include data and execute code bound from a string defined explicitly in the $scope. But - unless i'm going overlooking something after staring at the same stuff for a couple hours, the approach i'm using does not work with $scope data defined by XHR. Here's a plunkr to show the general idea implemented. Any suggestions would be greatly appreciated.
The HTML
<!DOCTYPE html>
<html data-ng-app="example">
<head lang="en">
<meta charset="UTF-8">
<title></title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.11.0/ui-bootstrap-tpls.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-sanitize.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="controller" >
<h1>Static Content</h1>
<p><button href="javascript: void(null)" role="link" ng-click="loadSubreport('recv_po_detail.rptdesign', 'static')">PO000007</button></p>
<h1>HTML from static string</h1>
<div compile="snippet"></div>
<h1>HTML from server string</h1>
<div compile="html.body"></div>
<hr />
<button ng-click="alert()">Show XHR Data</button>
</body>
</html>
The Javascript
var app = angular.module('example', []);
app.controller('controller', ['$scope', '$compile', '$http', function ($scope, $compile, $http){
$scope.snippet="<p><button href=\"javascript: void(null)\" ng-click=\"loadSubreport('recv_po_detail.rptdesign', 'compiled')\">PO000007</button></p>";
$http.get('data.json')
.success(function (data) {
$scope.html = data;
});
$scope.loadSubreport = function (filename, source) {
alert("Called from " + source);
};
$scope.alert = function () {{
alert($scope.html.body);
}}
}]);
app.directive('compile', ['$compile', function ($compile) {
"use strict";
return function (scope, element, attrs) {
var ensureCompileRunsOnce = scope.$watch(
function (scope) {
return scope.$eval(attrs.compile);
},
function (value) {
element.html(value);
$compile(element.contents())(scope);
ensureCompileRunsOnce();
}
);
};
}]);
Your watch goes off right at the start, when html.body still is undefined.
Then you run ensureCompileRunsOnce() and unwatch the scope. So the proper report, once loaded, never gets compiled.
I uncommented the line ensureCompileRunsOnce() and get a nice view of the report.
DEMO
I've been stuggling with angularjs services ans resource for a while, and can't get what I'm missing.
Here is a fiddle of my example:
http://jsfiddle.net/spacm/bfUVj/47/
(code below details)
This fiddle attempts to load periods (2012-2013,2013-2014...) from a web resource, to fill a select.
The fiddle doesn't work, I expect the $scope.perriodeJson to be filled by the periodes service. The http get request runs, but I only get an empty object, and don't get any update of the promise I expect.
Thanx for pointing what's wrong in this code, and suggesting enhancements.
<div ng-app='mod_periodes'>
<div id="appChoixPeriode" ng-controller='CtrlChoixPeriode'>
test:{{test}}<hr>
json periodes:{{periodeJson}}<hr>
Select periode:
<select ng-model="periodeSelect" ng-options="item.name for item in periodeSelectModel" ng-change="changePeriodeUtilisee()"></select>
<button type='button' ng-click='resetDefaultPeriode()'>G</button>
</div><!--appChoixPeriode-->
</div>
angular.module('mod_periodes', ['ngResource']);
angular.module('mod_periodes').factory('periodes', function($resource) {
var res = $resource('http://emm.menard.free.fr/test/fakereq.html');
/*content returned:
{"status":"success",
"data":{
"periodes":[
{"id_periode":"1","name":"2012-2013","ts_debut":"2012-07-01 00:00:00","ts_fin":"2013-06-30 23:59:59"},
{id_periode":"2","name":"2013-2014","ts_debut":"2013-07-01 00:00:00","ts_fin":"2014-06-30 23:59:59"},
{"id_periode":"3","name":"2014-2015","ts_debut":"2014-07-01 00:00:00","ts_fin":"2015-06-30 23:59:59"}
],
"id_periode":"2",
"temps_periode_utilisee":"present"},
"messages":[]}
*/
return res;
});
angular.module('mod_periodes').controller('CtrlChoixPeriode',implCtrlChoixPeriode);
function implCtrlChoixPeriode($scope, $resource, periodes) {
$scope.test="angular works";
$scope.periodeJson=periodes.get(); //why dont I get anything in $scope.periodeJson??
//the http request runs and looks successful
//below this, what I intended to do once I retrieve data
/* $scope.periodeJson=periodes.get(function() {
$scope.periodeSelectModel=$scope.periodeJson.data.periodes;
$scope.periodeSelect=$scope.periodeSelectModel[1];
});*/
// $scope.periodeSelectModel=$scope.periodeJson.data.periodes;
// $scope.periodeSelect=$scope.periodeSelectModel[1];
}
As pointed by ranru, my problem came from cross-domain issues.
Here is the exemple i ran locally:
<html>
<head>
<title>example</title>
<meta charset='utf-8'>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.2/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.2/angular-resource.min.js"></script>
<script>
angular.module('mod_periodes', ['ngResource']);
angular.module('mod_periodes').factory('periodes', function($resource) {
////////// here the url domain must be the same as the one hosting this page
//var res = $resource('http://myserv/fakereq.html');
/////////////////////////////
/*content returned:
{"status":"success",
"data":{
"periodes":[
{"id_periode":"1","name":"2012-2013","ts_debut":"2012-07-01 00:00:00","ts_fin":"2013-06-30 23:59:59"},
{id_periode":"2","name":"2013-2014","ts_debut":"2013-07-01 00:00:00","ts_fin":"2014-06-30 23:59:59"},
{"id_periode":"3","name":"2014-2015","ts_debut":"2014-07-01 00:00:00","ts_fin":"2015-06-30 23:59:59"}
],
"id_periode":"2",
"temps_periode_utilisee":"present"},
"messages":[]}
*/
return res;
});
angular.module('mod_periodes').controller('CtrlChoixPeriode',implCtrlChoixPeriode);
function implCtrlChoixPeriode($scope, $resource, periodes) {
$scope.test="angular works";
//this way, different $scope vars are set when the resource is received
$scope.periodeJson=periodes.get(function() {
$scope.periodeSelectModel=$scope.periodeJson.data.periodes;
$scope.periodeSelect=$scope.periodeSelectModel[1];
});
}
</script>
</head>
<body>
<div ng-app='mod_periodes'>
<div id="appChoixPeriode" ng-controller='CtrlChoixPeriode'>
test:{{test}}<hr>
json periodes:{{periodeJson}}<hr>
Select periode:
<select ng-model="periodeSelect" ng-options="item.name for item in periodeSelectModel" ng-change="changePeriodeUtilisee()"></select>
</div><!--appChoixPeriode-->
</div>
</body>
I try AngularJS for the first time and I'm stuck on a problem.
In the debugger I see that the scope variable '$scope.xml' is correctly updated, but the display needs a second pass (second click) to refresh.
Here is a Plunker to see my problem : http://plnkr.co/edit/9PJsGeDqwjC6nmZHcEJV
I'm looking in the documentation but I can not find track to understand what I did not do well
Thank's a lot for your help !
<!doctype html>
<html ng-app="testAngularJS">
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
</head>
<body>
<div ng-controller="testXML">
<div>XML<br/><textarea cols="60" rows="15" ng-model="xml" name="xml">{{xml}}</textarea></div>
<div><button ng-click="listTypDoc()">List !</button><br/>
<br/><button ng-click="clearXML()">Clear</button></div>
</div>
<script type="text/javascript">
var app = angular.module('testAngularJS', []);
app.controller('testXML', function($scope){
$scope.url = 'listeTypDoc.txt';
$scope.listTypDoc = function() {
$.ajax({
type:"GET",
url: $scope.url,
xhrFields: {
withCredentials: false
},
crossDomain: false
}).done(function ( data ) {
$scope.xml = data;
debugger;
});
};
$scope.clearXML = function() {
$scope.xml = '';
};
})
</script>
</body>
</html>
Because you are using a request outside the angularjs, you need to call $apply() after setting the data to the $scope.xml. Take a look in the apply method:
http://docs.angularjs.org/api/ng.$rootScope.Scope
But it's better to use the services angularjs provides instead of using jquery.