I'm quite new to Angularjs and I just can't figure out how to append a reply from $http() to a div(or any other element for that matter).
I've been using jQuery for a while and I know how to do it using that library, which is why I'm finding it hard to use Angular for this task.
I have a directive that uses $http.get() to get data from a PHP proxy. I'm trying to append the response from that $http() request to a div.
This is what I got right now:
app.directive('displayArticle', ['$http', '$log', function ($http, $log) {
var replyFromProxy = angular.element('<div></div>');
$http.get('gp-proxy.php').
success(function (data) {
// $log.info(data);
replyFromProxy = angular.element('<div>' + data + '</div>');
}).
error(function (data, status, headers, config) {
// $log.error(data);
// $log.error(status);
// $log.error(headers);
// $log.error(config);
});
return {
restrict: 'E',
templateUrl: 'templates/displayArticle.html',
compile: function (tElem) {
tElem.append(replyFromProxy);
}
};
}]);
displayArticle.html contains an empty div
What am I doing wrong?
Is there an easier or better way to do this?
Edit: What I'm trying to do is use gp-proxy.php to load an external page into my own webpage. The host doesn't allow CORS so this was my back-up plan.
Using ng-include in my template feels too static and not dynamic enough since I'd like to be able to load in different pages depending on what I click on in the original page.
Related
Currently I'm loading my firebase data right in my controller like this:
app.controller("MyCtrl", function ($scope, $firebaseObject) {
$scope.users = {};
var myDB = new Firebase('https://mydb.firebaseio.com/');
$firebaseObject(myDB.child("users")).$bindTo($scope, "user");
});
This way after the page is loaded, there is a delay during which the data is retrieved from firebase, therefore at first the page appears to be empty until the data arrives. This is unconvinient.
In order to prevent this flashy behavior I wanted to resolve the required data in my $routeProvider but wasn't able to get a promise.
How to properly get rid of the content flashing?
Is there a way to get a promise so one can resolve the $firebaseObject before the view is shown?
Please do not offer quick-and-dirty-solutions containing ng-cloak, ng-hide, ng-show etc.
You can use the $loaded() promise in your resolve function.
app.config(["$routeProvider", function($routeProvider) {
$routeProvider.when("/home", {
// the rest is the same for ui-router and ngRoute...
controller: "HomeCtrl",
templateUrl: "views/home.html",
resolve: {
"myObject": ["$firebaseObject", function($firebaseObject) {
var ref = new Firebase("...");
return $firebaseObject(ref).$loaded();
}]
}
})
https://www.firebase.com/docs/web/libraries/angular/guide/synchronized-objects.html
Check out the AngularFire docs on routing in authentication for better guidance on handling routes with promises in general.
https://www.firebase.com/docs/web/libraries/angular/guide/user-auth.html
Inside my Controller I have tried to stop $http being called multiple times, but my efforts seem to be in vein.
I only want the report's items to be loaded once.
Have tried checking for items being undefined and having a timesrun variable at the top of the Controller and increasing by 1 at the bottom of it.
if ($scope.items === undefined && $scope.timesrun == 0)
{
var req = {
method: 'GET',
*snipped*
};
$http(req).success(function (data, status, headers, config) {
$scope.items = data;
}).error(function (data, status, headers, config) {
SweetAlert.swal("Error " + status, data, "error");
});
}
I have even had this in a service but the service just gets called multiple times.
I'm clearly missing a trick. I can understand the digest cycle and I do have expressions in the page that need to be checked so I can see why the controller is running multiple times, but I cannot understand how I can get it to exclude the web calls after they've run once.
Being called $http service twice or more may be due to many reasons. Few I am listing below:
Do not mention controller (see : omit ng-controller='HomePanel' in html) name in template.
If you are using ngRoute, and mentioning controller name in template, as well in route config, it may be calling twice. For example. In app.js
app.config([ '$routeProvider', '$sceProvider',
function($routeProvider, $sceProvider) {
$routeProvider.when('/', {
templateUrl : 'Home',
controller : 'HomePanel',
});
}]);
and in HTML:
<script type="text/ng-template" id="Home">
<div ng-controller="HomePanel">
</div>
</script>
Don't let you ajax call to cache. So append some random value in end of your URL.
var req =
{
method: 'GET',
url : someUrl + "&random="+ Math.random();
};
Hope this may help.
Instead of using $http in controller put it in a function in a custom service and call that function when you want to update data from controller or you can call $http in service and assign it to a variable and use that in controller.
This might be a beginner question, but I am retrieving data via http calls in AngularJS and setting them as properties in the $scope variable. However, since http calls take a while, my page tries to load AngularJS more than once in order to render different parts of the page as more the data is retrieved. Is there a way around this? (to hold off on loading the page before all data has been retrieved)
What you could do is to use ng-hide or ng-cloak, so that whatever should not be displayed until the http call fully loaded the data would remain hidden.
take a look at the resolve property in the route settings. If you set something to be resolved the router will resolve this before going to the controller.
app.config(function ($routeProvider) {
$routeProvider
.when('/',
{
templateUrl: "app.html",
controller: "AppCtrl"
resolve: {
app: function ($q, $timeout) {
YourFactory.getData({});
}
}
}
)
});
then create a Factory that will get the data you need
app.factory('YourFactory', ['$http', '$q',
function($http, $q) {
var url = '/api2.php/api';
var YourFactory = {};
var factory_data = [];
var messages = [];
YourFactory.getData = function(params) {
console.log("into GET data");
var deferred = $q.defer();
$http.get(url).success(function(response) {
angular.copy(factory_data, response.data);
deferred.resolve();
}).error(function(response) {
//couldn't resolve therefore it's rejected
deferred.reject();
});
//returns a promise that indicates that something is being resolved and will be returned for the app to continue
return deferred.promise;
};
YourFactory.data = function() {
return factory_data;
};
return YourFactory;
}
]);
then in your controller you need to input the factory and set the scope data from the Factory. Remember that Angular used the Factory to get data before the controller using the resolve property.
app.controller("AppCtrl", ['$scope','YourFactory',
function($scope, YourFactory) {
$scope.data = YourFactory.data();
});
(I haven't tested the code, I simply wrote an example based on an app that I'am doing and in which I passed through the same things as you)
Look at this links if you have any doubt.
https://egghead.io/lessons/angularjs-resolve
http://www.javierlerones.com/2013/07/preloading-data-using-deferred-promises-in-angular-js.html
I am developing an application. In that i am retrieving the json data from an
external file using $http.get() method it worked fine. Now i am trying to use angular
restful services. it is working fine in filters, but when i use it in controller it is
displaying undefined.
//Service.js File
angular.module('calenderServices', ['ngResource']).
factory('Events', function($resource){
return $resource('/EventCalender/:File.json', {}, {
query: {method:'GET', params:{File:'events'}, isArray:true}
});
});
//This is my app Module
angular.module('calender', ['eventFilters','highlight','event','calenderServices']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('', {templateUrl: 'template.html', controller: MonthCtrl}).
otherwise({redirectTo: '/invalid'});
}]);
//This is my filter.js
angular.module('eventFilters', ['calenderServices']).filter('compare', function(Events) {
var events=Events.query();
alert(events[0].name); //it is displaying the name "Milestone1" });
//This is my controller.
function MonthCtrl($scope, Events){
var events=Events.query();
alert(events[0].name); //it is displaying undefined
}
//whenever i try to use the variable 'events' in controller, it is displaying undefined or null. But in filter it is working fine.
The following wont work because ngResource makes an asynchronous http request.
var events=Events.query();
alert(events[0].name); // <--- here events is an empty array
Usually all you need to do is the following and your data will be available to render in your view
$scope.events = Events.query()
It looks like a synchronous operation, but it isn't. This is angular's zen at work. You can learn the details from the docs.
To further process the data, you could also pass pass a success callback to the get method
Events.query(function(events){
// here you have access to the first event's name
console.log(events[0].name);
});
here's a working example: http://plnkr.co/edit/NDZ2JWjMUoUvtzEuRUho?p=preview
I am new to Angular and was able to create a basic page that create's a list of people with some checkboxes that allow you to choose them.
See this fiddle
The problems is that when I change the getAllPeople function to pull from a database
$http.post('angular.cfc?method=returnSerializeQuery').success(function(data) {
$scope.allPeople = data;
});
instead of building the array in the js the html loads to fast and loads with a blank list. if I then search the list shows up. I know that the $http call is too slow to keep up with the document load.
I have to use $timeout but I can't seem to get it to work an the dataset may sometimes take longer than other. If there is a Angular version of $(document).ready() I can't seem to find it.
I am also guessing that since this is my first fully functional page I am have not completely set it up right and that might have something to do with it.
If the idea is to delay the page rendering until data is fetched from the server, you have good answers (and examples) here and here.
The main idea:
function Ctrl($scope) {
$scope.data = {};
}
Ctrl.resolve = {
data: function($http) {
return $http({method: 'GET', url: '/path/to/some/data'});
}
};
var myApp = angular.module('app', [], function($routeProvider) {
$routeProvider.when('/', {
templateUrl: '/template.html',
controller: Ctrl,
resolve: Ctrl.resolve
});
});
Also check this working example: http://jsfiddle.net/dTJ9N/54/
In your post().success callback function, after $scope.allPeople = data; add $scope.groupToPages(), since ng-repeat is watching pagedItems, not allPeople.