Here is my issue:
The datatable plug-in only accepts an array I believe but my API returns an object with an array. I am trying to figure out if I need to extract this info (how?) or if the plug-in has some methods that do that for me (there is one):
//the datatable plugin expects the following JSON structure
[
{
"ID":"a5f415a7-3d4f-11e5-b52f-b82a72d52c35",
"Record":1,
"HostName":"SRX552P"
}
]
//my PHP server returns the following JSON structure:
{
"status":"success",
"message":"data retrieved",
"data":[
{
"ID":"a5f415a7-3d4f-11e5-b52f-b82a72d52c35",
"Record":1,
"HostName":"SRX552P"
}
]
}
var allData = null;
//this is my angularjs service where I am grabbing all the 'data':
function getAllData() {
dataservice.get('table001').then(function(data){
allData = data;
});
return allData;
}
//it looks like my issue is exactly what this post describes:
http://stackoverflow.com/questions/27797435/accessing-json-data-in-angularjs-datatables-using-dtoptions
//but applying ".withDataProp('data.data')" didn't work for me:
...
this.standardOptions = DTOptionsBuilder
.fromFnPromise(getAllData())
.withDataProp('data.data')
//.fromSource('api/tables/datatables.standard.json') //static data works fine!
//Add Bootstrap compatibility
.withDOM("<'dt-toolbar'<'col-xs-12 col-sm-6'f><'col-sm-6 col-xs-12 hidden-xs'l>r>" +
"t" +
"<'dt-toolbar-footer'<'col-sm-6 col-xs-12 hidden-xs'i><'col-xs-12 col-sm-6'p>>")
.withBootstrap();
this.standardColumns = [
DTColumnBuilder.newColumn('ID'),
DTColumnBuilder.newColumn('Record'),
DTColumnBuilder.newColumn('HostName')
];
...
//this is the service
(function () {
'use strict';
angular.module('app.ipxtool').factory('dataservice', dataservice);
dataservice.$inject = ['$http', '$q'];
function dataservice($http, $q) {
var serviceBase = 'api/v1/';
var obj = {};
obj.get = function (q) {
return $http.get(serviceBase + q).then(success).catch(fail);
};
function success(results) {
if (results.data.status == "error") {
logger.error(results.data.message, '', 'Error'); //$response["data"] = null for errors;
}
if (results.data.status == "warning") {
logger.warning(results.data.message, '', 'Warning');
}
if (results.data.status == "success") {
logger.success(results.data.message, results.data.data, 'Success'); //$response["data"] = $rows;
}
return results.data;
}
function fail(e) {
return (e);
}
return obj;
};
})();
Using Fiddler I can see all the data being returned. Also I output the first array item as follows:
console.log("var allData: " + "[" + JSON.stringify(alldata.data[1]) + "]");
The solution to this issue was to add the following:
.fromFnPromise(function() {
return dataservice.get('table001');
})
Not sure why calling getAllData() didn't work. So finally I got this thing resolved. Thanks.
You can add [ and ] at the start and at the end of your output var in php page itself, so that it would return a proper JSON output. Since I also faced such issue earlier in Angular as it doesn't accept direct Object input, I used the above approach to convert it into full-fledged JSON.
Also add the below code at the top of your PHP page:
header('Content-Type: application/json');
So that, it'll return the content in JSON-formatted text.
Related
I am building a website over a database of music tracks. The database is as follows :
music table contains musicid and title
musicrights table contains musicid and memberid
members table contains memberid and memberinfo.
I'm trying to build an array of objects in my database service, which each entry represents a track containing its rightholders (contains information aubout one rightholder but not his name) and their member info (contains name etc). The backend is sailsjs and the code is as follows :
angular.module("myapp").service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberid: rightHolder.memberid
})).then(function (res) {
rightHolder.member = res.data[0];
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/musicrights?where=" + JSON.stringify({
musicid: doc.musicid
})).then(function(res) {
// array of promises :
// each rightholder of a document has to solve member info
var rightHolders = [];
for (var i in res.data) {
var rightHolder = {
member: res.data[i].memberid,
type: res.data[i].membertype,
rights: res.data[i].memberrights
};
rightHolders.push(getHolderMember(rightHolder));
}
return ($q.all(rightHolders));
}).then(function(rightHolders) {
// expected array of one or two rightholders,
// enriched with member information
// actually returns array of one or two arrays of 30 members
// without rightholder info
console.log(rightHolders);
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
// array of 30 promises :
// each one of 30 documents has to resolve its rightholders
var documents = [];
for (var i in res.data) {
documents.push(getRightHolders(res.data[i]));
}
return ($q.all(documents));
}));
}
return (database);
}]);
The first array of promises seems to work as expected, but not the second one in getRightHolders. What is strange is that this function returns an array of one or two promises, which are rightHolders waiting for their memberinfo. But in the callback where I console.log the response, i get an array of one or two (as per the number of pushed promises) but this array's elements are arrays of 30 memberinfo instead of one memberinfo. I don't understand how this $q.all() call gets mixed with the previous-level $q.all.
The data structure is roughly like this
documents [ ] ($http => 30 responses)
music.musicid
music.rightHolders [ ] ($http => 1, 2, 3 responses)
rightholder.rights
rightholder.member ($http => 1 response)
member.memberinfo
Any help appreciated. Thank you !
UPDATE : Thank you for your answer, it worked like a charm. Here's the updated code, with also the migrate service which formats data differently (there is some database migration going on). I kept it out of the first example but your answer gave me this neat syntax.
angular.module("myApp").service("database", ["$q", "$http", "migrate", function($q, $http, migrate) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberID: rightHolder.member
})).then(function(res) {
return (migrate.member(res.data[0]));
}).then(function(member) {
rightHolder.member = member;
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/rightHolders?where=" + JSON.stringify({
musicID: doc.musicID
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.rightHolder)
.map(getHolderMember)
)
);
}).then(function(rightHolders) {
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
},
{
subtitle: {
contains: q
}
}
]
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.music)
.map(getRightHolders)
)
);
}));
}
return (database);
}
I'm not quite sure how you're getting the result you describe, but your logic is more convoluted than it needs to be and I think this might be leading to the issues you're seeing. You're giving the getRightsHolders function the responsibility of returning the document and based on your comment above, it sounds like you previously had the getHolderMember() function doing something similar and then stopped doing that.
We can clean this up by having each function be responsible for the entities it's handling and by using .map() instead of for (please don't use for..in with arrays).
Please give this a try:
angular
.module("myapp")
.service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(memberId) {
var query = JSON.stringify({ memberid: memberid });
return $http.get("/api/members?where=" + query)
.then(function (res) {
return res.data[0];
});
}
function populateRightsHolderWithMember(rightsHolder) {
return getHolderMember(rightsHolder.memberid)
.then(function (member) {
rightsHolder.member = member;
return rightsHolder;
});
}
function getRightHolders(doc) {
var query = JSON.stringify({ musicid: doc.musicid });
return $http.get("/api/musicrights?where=" + query)
.then(function(res) {
return $q.all(res.data.map(populateRightsHolderWithMember));
});
}
function populateDocumentWithRightsHolders(document) {
return getRightsHolders(document)
.then(function(rightsHolders) {
document.rightsHolders = rightsHolders;
return document;
});
}
database.music = function(q) {
return $http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
return $q.all(res.data.map(populateDocumentWithRightsHolders));
});
}
return (database);
}]);
Hi I am trying to update my data in angularJS(frontend) and laravel(backend).
But even I got an data from id, but I always make a new data.
I thought it cause my laravel code's fault, but not sure.
AngularJS service
app.factory('Assets', function($resource) {
return $resource('/api/assets/:assetId',{assetId:'#id'},{
update: {
method: 'PUT' // this method issues a PUT request
}
});
});
Controller (for data list)
app.controller('fixedAssetListCtrl',['$scope','$location','$rootScope','Assets', function($scope, $location, $rootScope,Assets){
$scope.assets = Assets.query();
$scope.goEdit = function(id){
Assets.query({assetId:id}.edit);
$location.path('/editFixedAsset').search({assetId:id});
}
}]);
Controller (for edit)
app.controller('fixedAssetEditCtrl',['$scope','$location','$rootScope','Assets',
function($scope, $location, $rootScope, Assets){
var edit_id=$location.path('/editFixedAsset').search();
var assetId=parseInt(edit_id.assetId);
//window.alert($rootScope.assetId.ID);
$scope.editassets = Assets.query({assetId});// getting data
// console.log($scope.editassets);
$scope.asset = {};
$scope.updateFixedAsset =function(asset){
var faData ={
detailAssetCode:$scope.detailAssetCode,
detailDescription:$scope.detailDescription,
detailParchaseDate:$scope.detailParchaseDate,
detailSoldDate:$scope.detailSoldDate
} //end of faData
Assets.update({assetId},asset);
}
}]);
Laravel Routes
Route::group(array('prefix' => '/api'), function () {
Route::resource('assets', 'AssetController');
});
Controller
public function show($id){
$assets = FAModel::find($id);
$response[] = [
'detailAssetCode' => $assets->AssetCode,
'detailDescription' => $assets->Description,
'detailPurchaseDate' => $assets->PurchaseDate,
'detailoldDate' =>$assets->SoldDate,
];
return Response::json($response, 200);
}
public function update($id){
$FAModelObj = new FAModel;
$fixedAssetData = FAModel::find($id);
$FAModelObj->AssetCode = Input::json('detailAssetCode');
$FAModelObj->Description = Input::json('detailDescription');//need to be JSON object??
$FAModelObj->PurchaseDate = Input::json('detailPurchaseDate');
$FAModelObj->SoldDate = Input::json('detailSoldDate');
$FAModelObj->push();
return Response::json(array('success'=>true));
}
Can you find the problem??
How can I change to update the data? Thanks.
The problem is that you create a new instance to save data instead of existing one. That's why new row is created in database. Your code should be like that.
public function update($id){
$fixedAssetData = FAModel::find($id);
$fixedAssetData->AssetCode = Input::json('detailAssetCode');
$fixedAssetData->Description = Input::json('detailDescription');//need to be JSON object??
$fixedAssetData->PurchaseDate = Input::json('detailPurchaseDate');
$fixedAssetData->SoldDate = Input::json('detailSoldDate');
$fixedAssetData->push();
return Response::json(array('success'=>true));
}
Hope it will be useful for you.
I'm having trouble decorate the objects in my list returned by $asArray in angularfire with a new method (not decorating the array itself).
The angularfire documentation seems to suggest that the right way to do this is to override the $$added method in the factory for $FirebaseArray, returning a new object that either encapsulates or extends the snapshot that gets passed in to that method. From the documentation:
// an object to return in our JokeFactory
app.factory("Joke", function($firebaseUtils) {
function Joke(snapshot) {
this.$id = snapshot.name();
this.update(snapshot);
}
Joke.prototype = {
update: function(snapshot) {
// apply changes to this.data instead of directly on `this`
this.data = snapshot.val();
},
makeJoke: function() {
alert("Why did the " + this.animal + " cross the " + this.obstacle + "?");
},
toJSON: function() {
// since we didn't store our data directly on `this`, we need to return
// it in parsed format. We can use the util function to remove $ variables
// and get it ready to ship
return $firebaseUtils.toJSON(this.data);
}
};
return Joke;
});
app.factory("JokeFactory", function($FirebaseArray, Joke) {
return $FirebaseArray.$extendFactory({
// change the added behavior to return Joke objects
$$added: function(snap) {
return new Joke(snap);
},
// override the update behavior to call Joke.update()
$$updated: function(snap) {
this.$getRecord(snap.name()).update(snap);
}
});
});
However, when I do this in my code, nothing ever gets added to the array, although I can see from outputting to the console that it is getting called.
var printMessageObjConstructor = function(snap) {
this.$id = snap.name();
this.snapshot = snap;
this.$update = function(snap) {
this.snapshot = snap;
};
this.printMessage = function() {
return this.author + "'s question is: " + this.body;
};
};
var ref = new Firebase("https://danculley-test.firebaseio.com/questions");
//What Am I Doing Wrong Here?
var arrayFactory = $FirebaseArray.$extendFactory({
$$added: function(snap, prevChild) {
var x = new printMessageObjConstructor(snap);
console.log("I am being called from FirebaseDecoratedCtlOverloadAddedinNewObj.");
return x;
},
$createObject: function(snap) {
return new printMessageObjConstructor(snap);
},
$$updated: function(snap) {
var i = this.$indexFor(snap.name());
var q = this.$list[i];
q.$update(snap);
}
});
var sync = $firebase(ref, {arrayFactory:arrayFactory});
var list = sync.$asArray();
list.$loaded(function(list) {
$scope.questions = list;
});
I've set up a new plunk stripped down to show the issue with a couple other use cases that I've tried. (The actual method I'm adding is more complex and isn't related to the view, but I wanted to do something simple to reproduce the issue.)
I think the issue is that I don't quite understand what exactly $$added is supposed to return, or what additional behavior beside returning the value to be stored $$added is supposed to have. There also doesn't really seem to be an $$added on the prototype or on $FirebaseArray to call as a super to get the default behavior. Can someone point me in the right direction?
UPDATE
For the benefit of others, after reviewing the like that Kato posted, I was able to solve the issue by adding the following, almost all copied directly from the source except for the commented line below.
$$added: function(snap, prevChild) {
var i = this.$indexFor(snap.name());
if( i === -1 ) {
var rec = snap.val();
if( !angular.isObject(rec) ) {
rec = { $value: rec };
}
rec.$id = snap.name();
rec.$priority = snap.getPriority();
$firebaseUtils.applyDefaults(rec, this.$$defaults);
//This is the line that I added to what I copied from the source
angular.extend(rec, printMessageObj);
this._process('child_added', rec, prevChild);
}
}
For the benefit of others, after reviewing the link that Kato posted, I was able to solve the issue by adding the following, almost all copied directly from the source except for the commented line below.
$$added: function(snap, prevChild) {
var i = this.$indexFor(snap.name());
if( i === -1 ) {
var rec = snap.val();
if( !angular.isObject(rec) ) {
rec = { $value: rec };
}
rec.$id = snap.name();
rec.$priority = snap.getPriority();
$firebaseUtils.applyDefaults(rec, this.$$defaults);
//This is the line that I added to what I copied from the source
angular.extend(rec, printMessageObj);
this._process('child_added', rec, prevChild);
}
}
I've been working through a few others, also this of looping through array to http.get data from a variety of sources. I understand that nodeJS is working asynchronously which is allowing the files to be written empty or with incomplete data, but I can't seem to get past this point.
Problem: calls are made, files are built but the files are always empty
Goal: loop through an array to create files locally from the sites data. Here is what I've got so far:
var file_url = 'http://js.arcgis.com/3.8amd/js/esri/',
DOWNLOAD_DIR = './esri/',
esriAMD = [ '_coremap.js', 'arcgis/csv.js'];
function readFile(callback) {
if (esriAMD.length > 0) {
var setFile = esriAMD.shift(),
file_name = url.parse(file_url).pathname.split('/').pop(),
trial = setFile.split('/').pop(),
file = fs.createWriteStream(DOWNLOAD_DIR + trial);
http.get(file_url + esriAMD, function(res) {
res.on('data', function(data) {
file.write(data);
console.log(setFile + ' has been written successfully');
});
res.on('end', function(){
console.log(setFile + ' written, moving on');
console.log(esriAMD.length);
readFile(callback);
});
//readFile(callback);
});
} else {
callback();
}
}
readFile(function() {
console.log("reading finishes");
});
Any insight would really help.
thanks,
var esriAMD = [....];
...
function readFile(callback) {
...
http.get(file_url + esriAMD, function(res) {
...
concatenating strings with arrays may yield unexpected results.
you want to make sure that
you know what URLs your program is accessing
your program deals with error situations (where the fsck is res.on('error', ...)?)
Solution: I was passing the wrong variable into the http.get
Working code:
var file_url = 'http://.....',
DOWNLOAD_DIR = './location/';
esriAMD = ['one', 'two', 'three'..0;
function readFile(callback) {
if(esriAMD.length > 0) {
var setFile = esriAMD.shift(),
file_name = url.parse(setFile).pathname.split('/').pop(),
trial = setFile.split('/').pop(),
file = fs.createWriteStream(DOWNLOAD_DIR + trial);
http.get(file_url + setFile, function(res){
res.on('error', function(err){
console.log(err);
});
res.on('data', function(data){
file.write(data);
console.log(setFile + ' started');
});
res.on('end', function(){
console.log(setFile + ' completed, moving on');
});
});
} else {
callback();
}
}
So I am trying storing product types from a json file before trying to add them to a collection but am getting some strange results (as in I dont fully understand)
on my router page i setup a variable for cached products as well as product types
cachedProductTypes: null,
productType : {},
products : {},
getProductTypes:
function(callback)
{
if (this.cachedProductTypes !== null) {
return callback(cachedProductTypes);
}
var self = this;
$.getJSON('data/product.json',
function(data)
{
self.cachedProductTypes = data;
callback(data);
}
);
},
parseResponse : function(data) {
result = { prodTypes: [], products: [] };
var type;
var types = data.data.productTypeList;
var product;
var i = types.length;
while (type = types[--i]) {
result.prodTypes.push({
id: type.id,
name: type.name,
longName: type.longName
// etc.
});
while (product = type.productList.pop()) {
product.productTypeId = type.id,
result.products.push(product);
}
};
this.productType = result.prodTypes;
console.log( "dan");
this.products = result.products;
},
showProductTypes:function(){
var self = this;
this.getProductTypes(
function(data)
{
self.parseResponse(data);
var productTypesArray = self.productType;
var productList=new ProductsType(productTypesArray);
var productListView=new ProductListView({collection:productList});
productListView.bind('renderCompleted:ProductsType',self.changePage,self);
productListView.update();
}
);
}
when a user goes to the show product types page it runs the showProductsType function
So I am passing the products type array to my collection
on the collection page
var ProductsType=Backbone.Collection.extend({
model:ProductType,
fetch:function(){
var self=this;
var tmpItem;
//fetch the data using ajax
$.each(this.productTypesArray, function(i,prodType){
tmpItem=new ProductType({id:prodType.id, name:prodType.name, longName:prodType.longName});
console.log(prodType.name);
self.add(tmpItem);
});
self.trigger("fetchCompleted:ProductsType");
}
});
return ProductsType;
now this doesnt work as it this.productTypesArray is undefined if i console.log it.
(how am I supposed to get this?)
I would have thought I need to go through and add each new ProductType.
the strange bit - if I just have the code
var ProductsType=Backbone.Collection.extend({
model:ProductType,
fetch:function(){
var self=this;
var tmpItem;
//fetch the data using ajax
self.trigger("fetchCompleted:ProductsType");
}
});
return ProductsType;
it actually adds the products to the collection? I guess this means I can just pass an array to the collection and do not have to add each productType?
I guess this means I can just pass an array to the collection and do not have to add each productType?
Yes, you can pass an array to the collection's constructor, and it will create the models for you.
As far as your caching code, it looks like the problem is here:
if (this.cachedProductTypes !== null) {
return callback(cachedProductTypes);
}
The callback statement's argument is missing this - should be return callback(this.cachedProductTypes).