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>
Related
test.html (my template):
<span data-ng-bind="emailSent.info"></span>
js:
$scope.resetPasswordEmail = "my#email.here";
// info is taken from a database with different languages
$scope.emailSent = {
info: getInfoFromDatabase() // returns: 'Confirmation email sent to {{resetPasswordEmail}}, check your email.'
};
angular.element(document.body).append($compile($templateCache.get('test.html'))($scope));
However this results in the following in the span on the page:
Confirmation email sent to {{resetPasswordEmail}}, check your email.
I'm attempting to do "nested" scope variables. Do I have to re-compile the compiled template again. Or is there a proper angularjs way of achieving this.
Based on your updated question, I see why you're doing this.
The key to do it is to use $interpolate:
angular.module('app', []).
controller('Ctrl', function($scope, $interpolate, $compile){
$scope.resetPasswordEmail = "my#email.here";
$scope.emailSent = {
info: $interpolate(getInfoFromDatabase())($scope)
};
function getInfoFromDatabase(){
return 'Confirmation email sent to {{resetPasswordEmail}}, check your email.'
}
angular.element(document.body).append($compile('<span data-ng-bind="emailSent.info"></span>')($scope));
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="Ctrl"></div>
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.
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'm trying to write an autocomplete directive that fetches data from the server using an $http request (without using any external plugins or scripts). Currently it works only with static data. Now, I know that I need to insert my $http request into the source: of the directive, but I can't find any good documentation on the subject.
http request
$http.post($scope.url, { "command": "list category() names"}).
success(function(data, status) {
$scope.status = status;
$scope.names = data;
})
.
error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
Directive
app.directive('autoComplete', function($timeout) {
return function(scope, iElement, iAttrs) {
iElement.autocomplete({
source: scope[iAttrs.uiItems],
select: function() {
$timeout(function() {
iElement.trigger('input');
}, 0);
}
});
};
});
View
<input auto-complete ui-items="names" ng-init="manualcat='no category entered'" ng-model="manualcat">
So, how do I piece this all together correctly the Angular way?
I made an autocomplete directive and uploaded it to GitHub. It should also be able to handle data from an HTTP-Request.
Here's the demo: http://justgoscha.github.io/allmighty-autocomplete/
And here the documentation and repository: https://github.com/JustGoscha/allmighty-autocomplete
So basically you have to return a promise when you want to get data from an HTTP request, that gets resolved when the data is loaded. Therefore you have to inject the $qservice/directive/controller where you issue your HTTP Request.
Example:
function getMyHttpData(){
var deferred = $q.defer();
$http.jsonp(request).success(function(data){
// the promise gets resolved with the data from HTTP
deferred.resolve(data);
});
// return the promise
return deferred.promise;
}
I hope this helps.
Use angular-ui-bootstrap's typehead.
It had great support for $http and promises.
Also, it doesn't include any JQuery at all, pure AngularJS.
(I always prefer using existing libraries and if they are missing something to open an issue or pull request, much better then creating your own again)
You need to write a controller with ng-change function in scope. In ng-change callback you do a call to server and update completions. Here is a stub (without $http as this is a plunk):
HTML
<!doctype html>
<html ng-app="plunker">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
<script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.4.0.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">
</head>
<body>
<div class='container-fluid' ng-controller="TypeaheadCtrl">
<pre>Model: {{selected| json}}</pre>
<pre>{{states}}</pre>
<input type="text" ng-change="onedit()" ng-model="selected" typeahead="state for state in states | filter:$viewValue">
</div>
</body>
</html>
JS
angular.module('plunker', ['ui.bootstrap']);
function TypeaheadCtrl($scope) {
$scope.selected = undefined;
$scope.states = [];
$scope.onedit = function(){
$scope.states = [];
for(var i = 0; i < Math.floor((Math.random()*10)+1); i++){
var value = "";
for(var j = 0; j < i; j++){
value += j;
}
$scope.states.push(value);
}
}
}
the easiest way to do that in angular or angularjs without external modules or directives is using list and datalist HTML5. You just get a json and use ng-repeat for feeding the options in datalist. The json you can fetch it from ajax.
in this example:
ctrl.query is the query that you enter when you type.
ctrl.msg is the message that is showing in the placeholder
ctrl.dataList is the json fetched
then you can add filters and orderby in the ng-reapet
!! list and datalist id must have the same name !!
<input type="text" list="autocompleList" ng-model="ctrl.query" placeholder={{ctrl.msg}}>
<datalist id="autocompleList">
<option ng-repeat="Ids in ctrl.dataList value={{Ids}} >
</datalist>
UPDATE : is native HTML5 but be carreful with the type browser and version.
check it out : https://caniuse.com/#search=datalist.
I found this link helpful
$scope.loadSkillTags = function (query) {
var data = {qData: query};
return SkillService.querySkills(data).then(function(response) {
return response.data;
});
};
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.