Sending JSON data to a method within my custom class - dojo

I am trying to send JSON data that's been loaded via dojo/request/xhr to a method within my custom class.
when I receive the data inside the .then() function I do not have access to my class instance methods since the data is only contained inside the .then() function call.
require([
"dojo/_base/declare",
"dojo/request/xhr"
], function(declare, xhr) {
declare("rpg.game",null, {
/**
*
* #param {type} domNode
* #returns {undefined}
*/
constructor: function(domNode) {
domNode.innerHTML = "hello world";
},
/**
*
* #param {type} _url
* #returns {undefined}
*
*/
loadData: function(_url) {
xhr(_url, {
handleAs: "json"
}).then(function(data){
// Do something with the handled data
console.log(data); // <-- How can I send this data to my class?
this.saveData(data); // <-- this does not work
}, function(err){
// Handle the error condition
}, function(evt){
// Handle a progress event from the request if the
// browser supports XHR2
});
},
saveData: function(data) {
this.data = data;
}
});
});
I want to send the data to the method saveData but when I call the method, it is "undefined" within the .then() call.

this doesn't reference your class since xhr call is asynchronous, your situation is similar to this issue with Promises.
You can bind proper context using lang.hitch from dojo/_base/lang (this will ensure that also this.data will use correct this):
require([
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/request/xhr"
], function(declare, lang, xhr) {
/*...*/
loadData: function(_url) {
xhr(_url, {
handleAs: "json"
}).then(lang.hitch(this, function(data){
// Do something with the handled data
console.log(data);
this.saveData(data); // <-- `this` should refer to your class
}),
Using var self = this; you'll have to set data directly in .then callback (or call saveData with context set to self)
loadData: function(_url) {
var self = this;
xhr(_url, {
handleAs: "json"
}).then(function(data) {
// Do something with the handled data
console.log(data);
self.data = data; // set `data` property of your class
// self.saveData(data); // <-- this does not work because of `this.data` in `saveData`
}, /**/);
},
saveData: function(data) {
this.data = data;
}

Related

CRUD Operation in JSONStore using MobileFirst Platform 7.1

I'm new to MFP and I'm trying to perform a basic CRUD operation. Nothing is happening after the following code is executed. I will highly appreciate if i can get some help. Thank you.
main.js
function wlCommonInit () {
var collections = {
people : {
searchFields: {name: 'string', age: 'integer'}
}
};
WL.JSONStore.init(collections).then(function (collections) {
// handle success - collection.people (people's collection)
}).fail(function (error) {
alert("alert" + error);
// handle failure
});
var collectionName = 'people';
var options = {};
var data = {name: 'yoel', age: 23};
WL.JSONStore.get(collectionName).add(data, options).then(function () {
// handle success
}).fail(function (error) {
// handle failure
});
// to display results using query yoel
var query = {name: 'yoel'};
var collectionName = 'people';
var options = {
exact: false, //default
limit: 10 // returns a maximum of 10 documents, default: return every document
};
WL.JSONStore.get(collectionName).find(query, options).then(function (results) {
// handle success - results (array of documents found)
}).fail(function (error) {
// handle failure
});
}//end wlCommonInit
JSONStore is asynchronous. With the code you wrote you cannot be sure of the order it is run.
The JavaScript code is most likely calling one of your add() or find() before your init() happens.
I would suggest you not writing the code within wlCommonInit because JSONStore may not be loaded yet. You could try tying it to a event like a button press or just put it into a function then call it in the console. Also, like #Chevy Hungerford has said, JSONStore is asynchronous so utilize the promises by chaining.
var collections = {
people : {
searchFields: {name: 'string', age: 'integer'}
}
};
// to display results using query yoel
var query = {name: 'yoel'};
var options = {
exact: false, //default
limit: 10 // returns a maximum of 10 documents, default: return every document
};
var collectionName = 'people';
var data = [{name: 'yoel', age: 23}]; //best if the data is an array
WL.JSONStore.init(collections).then(function (collections) {
// handle success - collection.people (people's collection)
return WL.JSONStore.get(collectionName).add(data);
})
.then(function (res){
return WL.JSONStore.get(collectionName).find(query, options)
})
.then(function (res){
//handle success - getting data
})
.fail(function (error) {
alert("alert" + error);
// handle failure
});

How to pull data from SqlDataAdapter and store it in a JsonStore collection in MobileFirst

I have a SqlDataAdapter and I want to store it in a JsonStore collection in MobileFirst and Display it in table form. I have tried using Load() method but its not working.
this is my resultSetCollection.js file
;(function () {
WL.JSONStore.init({
resultSet : {
searchFields: {"EMP_NAME":"string","EMP_ID":"integer"}
}
}, {
// password : 'PleaseChangeThisPassword'
})
.then(function () {
return WL.Client.invokeProcedure({
adapter : 'EmployeeList',
procedure : 'getEmployeeLists',
parameters : []
});
})
.then(function (responseFromAdapter) {
alert('responseFromAdapter:' + JSON.stringify(responseFromAdapter.invocationResult.resultSet));
var accessor = WL.JSONStore.get('resultSet');
var data=responseFromAdapter.invocationResult.resultSet;
var changeOptions = {
replaceCriteria : ['EMP_ID', 'EMP_NAME'],
addNew : true,
markDirty : false
};
return accessor.change(data, changeOptions);
})
.then(function (response) {
console.log(response);
//Here I want to retrieve the collection and display it in a table
})
.fail(function (errObj) {
WL.Logger.ctx({pretty: true}).error(errObj);
});
}());
An adapter procedure request from a client application will have a response object in its success and failure callbacks. So lets assume that the request was successfull and data was returned from the backend server.
Lets also assume you have a JSONStore initialized and properly setup with a collection. You then only need to get the collection and add data to it.
The below example takes the full response from an HTTP adapter request and puts it as-is into a collection. You will of course need to create a better setup for your specific scenario...
Note that the code is not optimised and performance or with 100% proper logic. It's just a demonstration flow.
Tested in MobileFirst Platform Foundation 7.0.0.00.
main.js:
var collectionName = 'mydata';
var collections = {
mydata : {
searchFields : {data: 'string'},
}
};
function wlCommonInit(){
WL.JSONStore.init(collections).then(
function() {
var resourceRequest = new WLResourceRequest("/adapters/myadapter/getStories", WLResourceRequest.GET);
resourceRequest.send().then(resourceRequestSuccess, resourceRequestFailure);
}
);
}
function resourceRequestSuccess(response) {
WL.JSONStore.get(collectionName).add(response).then(
function(){
WL.Logger.info("successfully added response to collection");
displayDataFromCollection();
},
function() {
alert("failed adding response to collection");
}
);
}
function resourceRequestFailure() {
alert ("failure");
}
If you then like to fetch the data from the JSONStore and display it in the HTML, you could do something like this:
// get a specific item from the stored response and display it in a table
function displayDataFromCollection() {
WL.JSONStore.get(collectionName).findAll().then(
function(result) {
$("#mytable").append("<tr><td>" + result[0].json.responseJSON.rss.channel.title + "</td></tr>");
},
function() {
alert ("unable to display collection");
}
);
}
The index.html looks like this:
<table id="mytable">
</table>

Using a json file to store configurations for a dojo application

I am writing a fontend web app using dojo that does a lot of calls to rest endpoints using xhr. I would like to have a place to store configurations for things like endpoint locations and html tag references. I thought I would use an xhr call to a json file to do this, but I am having trouble getting my functions to trigger in the right order/at all. Below is my main js file which has an init() function that I am passing as the callback to my conf initializer ("ebs/conf") module, also below. I have used the Chrome debugger to set breakpoints within my conf.get() method, and it looks as though it never gets called.
Can someone give me some advice please?
Main JS File:
// module requirements
require([ "dojo/dom", "dojo/on", "ebs/prices", "ebs/cart", "ebs/conf",
"dojo/ready" ], function(dom, on, prices, cart, conf, ready) {
ready(function() {
conf.get("/js/config.json", init());
function init(config) {
on(dom.byId("height"), "keyup", function(event) {
prices.calculate(config);
});
on(dom.byId("width"), "keyup", function(event) {
prices.calculate(config);
});
on(dom.byId("qty"), "keyup", function(event) {
prices.calculate(config);
});
on(dom.byId("grills"), "change", function(event) {
prices.calculate(config);
});
cart.putSampleCart();
cart.load(config);
}
});
});
And here is my 'conf' module ("ebs/conf"):
define(["dojo/json", "dojo/request/xhr"], function(json, xhr) {
return {
get : function(file, callback) {
// Create config object from json config file
var config = null;
xhr(file, {
handleAs : "json"
}).then(function(config) {
callback(config);
}, function(error) {
console.error(error);
return error;
});
}
}
});
Your are not passing the function as the callback. You are executing it and passing the result as the second argument.
conf.get("/js/config.json", init());
should be
conf.get("/js/config.json", init);

How to broadcast to other controllers when load with module.config or .run in Angularjs

I have a checking when reading the web page,then using the result to refresh sidebar by ng-repeat,but I have errors :
Uncaught Error: Unknown provider: $scope from myModule or
Uncaught Error: Unknown provider: $scope from sharedService
How can I resolve it?
Here is my code
module:
var myModule = angular.module('myModule', []);
service for broadcast:
myModule.factory('mySharedService', function($rootScope) { //service
var sharedService = {};
sharedService.keyHistory = [];
sharedService.linkHistory = [];
sharedService.prepForBroadcast = function(key,link) {
this.keyHistory = key;
this.linkHistory = link;
this.broadcastItem();
};
sharedService.prepForBroadcastAdd =function(key){
console.log(this.keyHistory.push(key));
//this.linkHistory = linkHistory+link;
this.broadcastItem();
};
sharedService.broadcastItem = function() {
$rootScope.$broadcast('handleBroadcast');
};
return sharedService;
});
config to do Checking:
myModule.config(function($scope,sharedService){
$.ajax({
url:"/fly/AJAX",
type:"POST",
contentType:'application/x-www-form-urlencoded; charset=UTF-8',
datatype:"json",
success:function(data){
if(data!=null){
var loginResult = $.parseJSON(data);
if (loginResult.success == true){
console.log("login success");
$("#userLable").html(loginResult.userName+'('+loginResult.loginID+')');//
if (loginResult.hasHistory==true) {
sharedService.prepForBroadcast(loginResult.searchHistory,[]);
console.log("broadcast");
}
};
}
}
});
});
SideCtrl:
function SideCtrl($scope,sharedService) {
$scope.$on('handleBroadcast', function() {
$scope.keyHistory =sharedService.keyHistory;
$scope.linkHistory = sharedService.linkHistory;
});
}
SideCtrl.$inject = ['$scope', 'mySharedService'];
THX !
The error is due to trying to request a $scope in a config block, which you can't do. If I understand what you're trying to do, then I also think you're over-complicating it. I'd solve the problem a little differently. The details would depend on your requirements and use case, but based on the information you gave...
I'd have a service responsible for communication with the server and storing the state:
app.factory( 'loginService', function ( $http ) {
var result;
function doRequest( data ) {
// just flesh out this post request to suit your needs...
return $http.post( '/fly/ajax', data, {} )
.then( function ( response ) {
// assuming you don't care about the headers, etc.
return response.data;
});
}
// Do it once initially
if ( ! angular.isDefined( result ) ) {
result = doRequest();
}
// return the service's public API
return {
getStatus: function () { return result; },
login: doRequest
};
});
Now the first time this service is requested, the $http request will be made. If you're accessing this from multiple controllers, the post will only occur once because of the isDefined statement. You can then use this in your controllers:
app.controller( 'MainCtrl', function( $scope, loginService ) {
loginService.getStatus().then( function ( data ) {
// do whatever you need to with your data.
// it is only guaranteed to exist as of now, because $http returns a promise
});
});
Every controller accesses it the same way, but it was still only called once! You can set values against the scope and access it from your views, if you want:
app.controller( 'MainCtrl', function( $scope, loginService ) {
loginService.getStatus().then( function ( data ) {
$scope.loginId = data.loginID;
});
});
And in your view:
<h1>Welcome, {{loginId || 'guest'}}!</h1>
And if you need to, you call the function again:
app.controller( 'MainCtrl', function( $scope, loginService ) {
// ...
loginService.login( $scope.user ).then( function ( data ) {
$scope.loginId = data.loginID;
});
// ...
});
As you can see, broadcasting an event is totally unnecessary.
I would do it differently. I would create some sort of more top-level controller, like function MainController($rootScope, $scope, sharedService) and wire it up with body: <body ng-controller='mainController' ng-init='init()'. After that you should create init() method in MainController.
Inside this initialization method I would call sharedService which should make AJAX request (via $http! that's the best practice, and it's very similar to jQuery) and broadcast proper event when required.
That way you make sure to call initialization just once (when MainController is initializing), you stick to the angular's best practices and avoid dodgy looking code.

Accessing ioArgs from callback functions

I'm upgrading a bunch of old dojo to 1.8. For our ajax request handling we've got a decorator (well, function wrapper) that will perform redirects in certain cases based on the response content, for example:
// Decorator func:
var redirectDecorator = function(func) {
var f = function(data, ioArgs) {
if(data.redirect) {
// A manual location redirect:
window.location.href = data.redirect;
if(data.redirect_xhr) {
// clone ioArgs, spawn new request to follow redirect etc
// <snip>
} else {
func(response);
}
}
return f;
}
// Used like so:
dojo.xhrPost({
url: url
handleAs: "json",
form: form,
load: redirectDecorator(function(data, ioArgs) {
// do stuff
})
});
Now, in dojo 1.8 (the dojo/request/xhr module) xhr() returns a Deferred for chaining and the callbacks are only supplied the data argument (no ioArgs - apparently these are attached to the promise - see http://bugs.dojotoolkit.org/ticket/12126).
In other words, the above ajax call becomes:
xhr.post(url, {
handleAs: "json",
form: form
}).then(function(data) {
// do stuff
});
Problem is, I can no longer wrap the anonymous function because ioArgs are not supplied. Inspecting the deferred (by breaking the chaining) doesn't appear to work either and would require more re-engineering than I'd like.
Any ideas?
Thanks Ken (for your help at #dojo too). To elaborate, the solution is to use dojo/request and use the .response deferred promise instead, which provides the necessary info:
// Decorator func:
var redirectDecorator = function(func) {
var f = function(response) {
var data = response.data;
if(data.redirect) {
// A manual location redirect:
window.location.href = data.redirect;
if(data.redirect_xhr) {
request(data.redirect_xhr, response.options).then(func);
} // more conditions follow.
}
return f;
}
request.post(url, {
handleAs: "json",
form: form
}).response.then(redirectDecorator(function(response) { // <-- note .response.then(
// do stuff where data is response.data
}));
Promises returned from dojo/request are actually objects with an additional response promise that provides more information. See the following places for information:
http://www.sitepen.com/blog/2012/08/21/introducing-dojorequest/
http://dojotoolkit.org/reference-guide/1.8/dojo/request.html
http://dojotoolkit.org/documentation/tutorials/1.8/ajax/