I'm using Angular wp-api module and each time my $resource request responds I can see the ResponseHeaders in Chrome with X_Total_Pages and other header information. But I cannot add them to the scope.
Here is my controller...
.controller('newslettersController', ['$scope','$stateParams','$sce','WPFactory', function ($scope,$stateParams,$sce,WPFactory) {
$scope.newsletters = WPFactory.query({
param1: 'posts',
page: $scope.pageNum,
'filter[cat]': 8,
'filter[posts_per_page]' : 10,
'filter[orderby]': 'ID'
}, function(data, reponseHeaders) {
$scope.header = reponseHeaders('X_Total_Pages');
});
});
}]);
And my factory...
.factory("WPFactory", function($resource) {
var dataResponse = $resource('http://www.example.com/wp-json/:param1/:param2/:param3/:param4/:param6/:param7', {}, {
get: {
method: 'GET'
}
});
return dataResponse;
})
is this jeffsebrings angular module? If it is I think you need to inject your service with wpAPIResource:
.factory("WPFactory", function($resource, wpAPIResource)
and use it to query the json rest api (wp-api).
Also, not sure if your controller is passing the query object quite right:
I would change up your factory something like this:
.factory("WPFactory", function(wpAPIResource) {
var posts_query = function(args) {
return wpAPIResource.query(args);
};
return posts_query;
})
Related
I have two mongoose schemas running in on my server end. I would like to add two $http.get request in my app.js and eventually display two tables from my collection in MongoDB on a webpage. Only one get function is called without errors.
server.js
//Data Schema
var tempSchema = new mongoose.Schema({
topic: String,
message: Number,
when: Date
}, {collection: "temperature"});
var humiditySchema = new mongoose.Schema({
topic: String,
message: Number,
when: Date
}, {collection: "humidity"});
var temperature =mongoose.model('temperature', tempSchema);
var humidity =mongoose.model('humidity', humiditySchema);
app.js
app.controller("FormController", function ($http, $scope){
$http.get("/api/temperature")
.then(function (response) {
$scope.temperatures = response.data;
});
})
app.controller("FormController", function ($http, $scope){
$http.get("/api/humidity")
.then(function (response) {
$scope.humiditys = response.data;
});
})
Also thinking of how I can display both collections on the webpage. Using ng-repeat. Unfortunately I cannot paste my HTML code here.
I would appreciate any help I can get. Thanks
Another way you could handle the $http requests is by creating an Angular Factory.
angular.module('myApp.services',[])
add.factory('ApiService', function($http) {
return {
getHumidity: function() {
return $http.get("/api/humidity");
},
getTemperature: function() {
return $http.get("/api/temperature");
}
}
})
Then inside your controller, you should do the following (Note that you must inject the factory as a dependency for the controller)
angular.module('myApp.controllers',[])
.controller("FormController", function (ApiService, $scope){
function getHumidity() {
var promise = ApiService.getHumidity();
promise.then(
function(response) {
$scope.humiditys = response.data;
},
function(errorPayload) {
console.log(errorPayload);
});
};
function getTemperature() {
var promise = ApiService.getTemperature();
promise.then(
function(response) {
$scope.temperatures = response.data;
},
function(errorPayload) {
console.log(errorPayload);
});
};
getHumidity();
getTemperature();
})
then where you define your angular App (app.js in most of the cases):
angular.module('myApp', ['myApp.controllers','myApp.services'])
.run(...)
.config(...)
...
I am just starting out with Angular and trying to adapt a tutorial I have been following.
I have a resource defined as:
.factory('Session', function ($resource) {
return $resource('http://localhost/api/sessions');
});
I am trying to use the response with a controller like this:
.controller('SessionsCtrl', function($scope, Session) {
$scope.sessions = Session.query();
})
The problem I am coming up against is the format of the JSON response has the sessions in a subproperty as such:
{
sessions: [
{
id: 1,
title: "Welcome"
{
id: 2,
title: "Session 1"
}
]
}
How do I get the resource to look as the sessions property?
If your service is sending an object instead of an array, you should add isArray: false to its declaration:
yourApp.factory('Session', function ($resource) {
return $resource(
'http://localhost/api/sessions',
{},
{'query': {method: 'GET', isArray: false }}
);
});
In your controller you can use a callback:
yourApp.controller('SessionsCtrl', function($scope, Session) {
$scope.sessions = Session.query(function(result) {
return result.sessions;
});
});
I am very new with AngularJS. Thank you for answer. My code is as follow:
mainModule.controller('MainController', function($scope, $http) {
$http.get('http://localhost/backend/WebService.php', {params: {entity: 'IndexPageEntity'}}).
success(function(data) {
$scope.intro = data[0].IndexPageContent;
});
$http.get('http://localhost/backend/WebService.php', {params: {entity: 'ExhibitionServiceEntity'}}).
success(function(data) {
$scope.exhibit = data[0].ExhibitionServiceContent;
});
$http.get('http://localhost/backend/WebService.php', {params: {entity: 'ShootingServiceEntity'}}).
success(function(data) {
$scope.shooting = data[0].ShootingServiceContent;
});
});
My html file would be:
<div ng-controller="MainController">
<div>{{intro}}</div>
<div>{{exhibit}}</div>
<div>{{shooting}}</div>
</div>
I believe there must be some ways to improve the above code in order to reduce repetition. What I want is to pass entity parameter to the controller on creation.
Using ng-init to pass parameter is discouraged, according to the documentation. Writing custom directive to pass argument to scope does not work since parameters would be overwrittern.
What is the best practice to set params dynamically for use in $http? Thank you.
You should move all the logic to a service and use a directive. I would suggest you to modify your backend to return the same structured data, instead of IndexPageContent, ExhibitionServiceContent, etc. it should be Content or whatever name you want to use. But for now I've added a replace function to get the name of the content from the name of the entity.
mainModule.factory('webService', function($http) {
var apiUrl = 'http://localhost/backend/WebService.php';
function getContent(params) {
var config = {
'params': params
};
return $http.get(apiUrl, config);
};
return {
getContent: function(params) {
return getContent(params)
}
};
});
mainModule.controller('MainController', function($scope, webService) {
var params = {
'entity': $scope.entity
};
var contentName = $scope.entity.replace('Entity', 'Content');
webService.getContent(params).then(function (data) {
$scope.content = data[0][contentName];
});
});
mainModule.directive('EntityContent', function() {
return {
controller: 'MainController',
replace: true,
restrict: 'E',
scope: {
entity: '#entity'
},
template: '<div>{{ content }}</div>'
};
});
<div>
<entity-content entity="IndexPageEntity">
<entity-content entity="ExhibitionServiceEntity">
<entity-content entity="ShootingServiceEntity">
</div>
Create an object data and send the value for the key inside the object at every call.. Also pass the value for key to be set inside the scope..
E.g.
$scope.makeHttpCall = function(data) {
$http.get('http://localhost/backend/WebService.php', {params: data}).
success(function(data) {
$scope[$scope.key] = data[0][$scope.key];
});
};
you can then call this function as
$scope.key = 'IndexPageContent';
data = {
entity : 'yourValueHere'
};
$scope.makeHttpCall(data);
You can set other values as well inside the scope that are dynamic for each request..
I hope this makes sense to you...
I'am not pro in Angular and am still lerning. Hope I get some help here.
I want to build an App with different views. I need to detect the browser and also fetch some data from a server. For this I created a service, where I do this work.
My desire is to use the data of the service all views. How is proper way to store and cache the data so that I can use it in all my Views/Controllers?
Here is what I got so far.
My Service:
.factory('DataService', function($http, $q, $timeout) {
var data = { };
return {
notes: function() {
// This exposed private data
return data;
},
addItem: function(itemname, itemvalue) {
// This is a public function that modifies private data
data[itemname] = itemvalue;
}
getPlatform: function() {
var getPlatformData = function() {
var deferred = $q.defer();
BrowserDetect.init();
deferred.resolve(BrowserDetect.OS);
return deferred.promise;
};
return {
getPlatformData: getPlatformData
};
},
getServerData: function() {
//if(!data.getServerData){
var getData = function() {
var deferred = $q.defer();
$http({
url: 'js/fakeGet.json',
method: 'get',
dataType: 'json',
}).success(function(data) {
data.scanResponse = data;
deferred.resolve(data);
})
return deferred.promise;
};
return {
getData: getData
};
//}
// return data.scanResponse;
}
};
});
My controller:
DataService.getPlatform().getPlatformData().then(function(platform) {
console.log('Another browserDetect request');
$scope.platform = platform;
DataService.addItem("platform", $scope.userPlatform);
});
First of all, as nordyke mentioned in his answer, you'd better split the service to smaller ones.
Second, you're asking for how to caching the data, and since you're using promise, $q.when() is what you need. I will take the getPlatform as an example to get you started:
.factory('DataService', function($http, $q, $timeout) {
var os; // this variable is used to store the result
return {
getPlatform: function() {
var getPlatformData = function() {
if (!os) { // no previous data available, look into other service to fetch the data
var deferred = $q.defer();
BrowserDetect.init();
os = BrowserDetect.OS; // store data
deferred.resolve(os);
return deferred.promise;
}
return $q.when(os); // there is previous data, return it as promise
};
return {
getPlatformData: getPlatformData
};
}
};
});
In this way, OS information is cached, and
DataService.getPlatform().getPlatformData().then(function(platform) {
...
});
will only fetch the platform information once during the life-time of the DataService. You can apply the same idea to getServerData as well to cache the data from the server.
Caching your data in a service singleton is a good approach, and I like your straightforward implementation of it. My only recommendation would be to split up your 3 concerns into separate services.
Browser Detection
Server Requests (which will be split up even more once you have more requests.)
Data Caching
That might be strange but I need to specify some default POST data for my $resource using the factory method of the module.
Does anyone have an idea of how to do that in AngularJS ?
EDIT :
Well, i want to do something like this :
/**
* Module declaration.
* #type {Object}
*/
var services = angular.module("services", ["ngResource"]);
/**
* Product handler service
*/
services.factory("Product", function($resource) {
return $resource("http://someUrl", {}, {
get : {method: "GET", params: {productId: "-1"}},
update: {method : "POST", params:{}, data: {someDataKey: someDataValue}}
});
});
Where data is the default data for my future POST requests.
This is not really the angular way to do such a thing as you lose data consistency if you do it and it doesn't reflect in your model.
Why?
The resource factory creates the object and uses object instance data as POST. I have looked at the documentation and angular-resource.js and there doesn't seem to be a way to specify any default custom properties for the object being created by resource without modifying angular-resource.js.
What you can do is:
services.factory("Product", function($resource) {
return $resource("http://someUrl", {}, {
get : {method: "GET", params: {productId: "-1"}},
update: {method : "POST"}
});
});
and in your controller:
$scope.product = {}; // your product data initialization stuff
$scope.product.someDataKey = 'someDataValue'; // add your default data
var product = new Product($scope.product);
product.$update();
I think it will depend on how you call the update function. If you read the angular main page's tutorial, under "Wire up a Backend", the mongolab.js provides a 'Project' factory. Copied verbatim:
angular.module('mongolab', ['ngResource']).
factory('Project', function($resource) {
var Project = $resource('https://api.mongolab.com/api/1/databases' +
'/angularjs/collections/projects/:id',
{ apiKey: '4f847ad3e4b08a2eed5f3b54' }, {
update: { method: 'PUT' }
}
);
Project.prototype.update = function(cb) {
return Project.update({id: this._id.$oid},
angular.extend({}, this, {_id:undefined}), cb);
};
Project.prototype.destroy = function(cb) {
return Project.remove({id: this._id.$oid}, cb);
};
return Project;
});
The usage is that you first get an instance of the Project:
project = Project.get({id:1});
Then do an update after some changes:
project.update(someFunction);
In your case, you can change the update to always add the data you need:
Product.prototype.update = function(cb) {
return Product.update({},
angular.extend({}, this, {someDataKey: someDataValue}), cb);
};
Otherwise, you can most likely put the key/value pair in the params:
update: {method : "POST", params:{someDataKey: someDataValue}}
It will be POSTed with the key/value pair in the URL, but most app servers nowadays will throw the pair into the params object anyway.
I think most have missed a tiny gem in the documentation here.
non-GET "class" actions: Resource.action([parameters], postData, [success], [error])
This suggests you can do the following.
var User = $resource('/user');
postData = { name : 'Sunil', 'surname' : 'Shantha' };
var user = User.save({notify:'true'}, postData, function() {
// success!
});
The second parameter when doing a save action (post) is post data.
Wrapper function will work.
function myPost(data) {
return $http.post('http://google.com', angular.extend({default: 'value'}, data))
}
myPost().success(function(response) { ... });
Might this solve your problem?
services.factory("Product", function($resource) {
return $resource("http://someUrl", {}, {
get : {method: "GET", params: {productId: "-1"}},
update: {method : "POST", params:{}, data: {someDataKey: someDataValue}}
});
});
services.factory("DefaultProduct", function(Product) {
return function(){
return new Product({
data:"default";
});
};
});
services.controller("ProductCTRL",function($scope,DefaultProduct){
$scope.product = new DefaultProduct();
});
You can just merge your params with the default. Everything not available in params will be provided by the default object. Everything available will be overwritten by myParams
services.factory("Product", function($resource) {
return $resource("http://someUrl", {}, {
get : {method: "GET", params: {productId: "-1"}},
update: {method : "POST", params:angular.extend(myDefault, myParams);}
});
});
where myParams would be your list of variables and myDefault your default values as a json object.
You can set default fields on your request by using transformRequest option for your $resource's actions that use the POST method.
For example something like this
function prependTransform(defaults, transform) {
// We can't guarantee that the default transformation is an array
defaults = angular.isArray(defaults) ? defaults : [defaults];
// Append the new transformation to the defaults
return [transform].concat(defaults);
}
ctrl.factory('MyResource', ['$resource', '$http',
function($resource, $http) {
return $resource('/path/to/myresource/:id', {id : '#id'},
{
create : {
method : 'POST',
transformRequest : prependTransform($http.defaults.transformRequest,
function(data, headers) {
return addDefaultField(data);
}
),
},
});
}
]);