Rally SDK Lookback API with Deft Promises Gives Error - rally

I'm trying to use the Rally Lookback API with Deft Promises. The code below works with wsapi store, but not the snapshot store. Shouldn't the snapshot store work the same? The error received is: TypeError: Cannot read properties of undefined (reading 'getProxy') How to make this work with the snapshot store?
launch: function() {
Deft.Promise.all([
this.loadRecords('UserStory'),
this.loadRecords('Defect'),
this.loadRecords('TestCase')
]).then({
success: function(recordSets) {
// recordSets = [
// UserStoryRecords,
// DefectRecords,
// TestCaseRecords
// ];
console.log(recordSets);
},
failure: function() {
//Handle error loading the store here...
console.log("Failed.");
}
});
}, // end launch
loadRecords: function(model) {
var deferred = Ext.create('Deft.Deferred');
// Ext.create('Rally.data.wsapi.Store', { // This works!
Ext.create('Rally.data.lookback.SnapshotStore', { // TypeError!!
limit: 'infinity',
model: model,
fetch: ['Name', 'ObjectID'],
autoload: true
}).load({
callback: function(records, operation, success) {
if (operation.wasSuccessful()) {
deferred.resolve(records);
} else {
deferred.reject('Rejected');
}
}
});
return deferred.promise;
},

So it looks like I found the answer, you don't use model in SnapshotStore requests, pass the name of the data store you want to a _TypeHierarchy filter as such. Below appears to work as expected.
launch: function() {
Deft.Promise.all([
this.loadRecords('HierarchicalRequirement'),
this.loadRecords('Defect'),
this.loadRecords('TestCase')
// do some more stuff
]).then({
success: function(recordSets) {
// recordSets = [
// UserStoryRecords,
// DefectRecords,
// TestCaseRecords
// ];
console.log(recordSets);
},
failure: function() {
//Handle error loading the store here...
console.log("Failed.");
}
});
}, // end launch
loadRecords: function(model) {
var deferred = Ext.create('Deft.Deferred');
Ext.create('Rally.data.lookback.SnapshotStore', {
limit: 'infinity',
// model: model, // Doesn't work => TypeError
fetch: ['Name', 'ObjectID'],
autoload: true,
filters: [{
property: '_TypeHierarchy',
operator: 'in',
value: [model] // WORKS!!
}]
}).load({
callback: function(records, operation, success) {
if (operation.wasSuccessful()) {
deferred.resolve(records);
} else {
deferred.reject('Rejected');
}
}
});
return deferred.promise;
}

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
});

Add a auto initialize function inside a Sencha Touch model to manipulate model's data

When I load a store, due to the API structure, I get a json object inside my model:
Ext.define('TestApp.model.SecretKeyModel', {
extend: 'Ext.data.Model',
config:{
identifier: {
type: 'uuid'
},
fields: [
{ name:'theRecord', type:'json' }
]
},
extractToken: function() {
var record = this;
var token = record.initSession.token;
console.log('token: ' + token);
}
});
I need to extract the token from that json object.
For that, i think I should write a function right there, inside the model.
How can I call it, when the store loads, to manipulate the data and extract the token?
I faced a similar situation 1 hour ago, i needed to edit data during loading or immidiatly after. I ended with this solution:
Ext.define('TestApp.store.MyStore', {
extend: 'Ext.data.Store',
requires: ['TestApp.model.SecretKeyModel'],
config :{
model: 'TestApp.model.SecretKeyModel',
proxy: {
type: 'ajax',
url: TestApp.utils.GlobalVariables.getServerUrl(),
reader: {
type: 'json',
rootProperty: ''
}
},
listeners: {
refresh: function(store, data, eOpts) {
store.each(function (item, index, length) {
item.extractToken(); // call this on every record loaded in the store
});
}
}
}
});

Sencha Touch 2, before filter on the router, to check for user's auth state

I am developing a Sencha Touch 2 app with user authentication.
I use a token for authentication.
The logic.
Check is a token exists in local storage:
var tokenStore = Ext.getStore('TokenStore'),
token = tokenStore.getAt(0).get('token');
If there is a token, check if it's valid.
I am doing a read from a model which is connected to my API which, returns success or fail - depending on the token - if it's valid or not.
TestApp.model.CheckAuthModel.load(1, {
scope: this,
success: function(record) {
// Here, I know the token is valid
},
failure: function() {
console.log('failure');
},
callback: function(record) {
console.log('callback');
console.log();
}
});
And here is the router, which handles the logic for the views:
Ext.define("TestApp.controller.Router", {
extend: "Ext.app.Controller",
config: {
refs: {
HomeView: 'HomeView',
LoginView: 'LoginView',
ProductsView: 'ProductsView',
ProductsViewTwo: 'ProductsViewTwo'
},
routes: {
'': 'home',
'home' : 'home',
'login' : 'login',
'products' : 'products',
'testingtwo' : 'testingtwo'
}
},
home: function () {
console.log('TestApp.controller.Router home function');
var initialItem = Ext.Viewport.getActiveItem(),
comp = this.getHomeView();
if (comp === undefined) comp = Ext.create('TestApp.view.HomeView');
Ext.Viewport.animateActiveItem(comp, {
type: 'slide',
listeners: {
animationend: function() {
initialItem.destroy();
}
}
});
},
login: function () {
var initialItem = Ext.Viewport.getActiveItem(),
comp = this.getLoginView();
if (comp === undefined) comp = Ext.create('TestApp.view.LoginView');
Ext.Viewport.animateActiveItem(comp, {
type: 'slide',
listeners: {
animationend: function() {
initialItem.destroy();
}
}
});
},
products: function () {
var initialItem = Ext.Viewport.getActiveItem(),
comp = this.getProductsView();
if (comp === undefined) comp = Ext.create('TestApp.view.ProductsView');
Ext.Viewport.animateActiveItem(comp, {
type: 'slide',
listeners: {
animationend: function(){
initialItem.destroy();
}
}
});
},
testingtwo: function () {
var initialItem = Ext.Viewport.getActiveItem(),
comp = this.getProductsViewTwo();
if (comp === undefined) comp = Ext.create('TestApp.view.ProductsViewTwo');
Ext.Viewport.animateActiveItem(comp, {
type: 'slide',
listeners: {
animationend: function(){
initialItem.destroy();
}
}
});
},
launch: function() {
console.log('TestApp.controller.Router launch!');
}
});
Now, how can I link the router with the check auth model callback?
I want to know the auth state when the app reaches the router.
In other MVC frameworks, I could do a before filter, on the router, check for auth and handle the routes accordingly.
Can i do this in Sencha Touch 2?
Any ideas?
Hi I think this section in the documentation is exactly what you need:
before : Object
Provides a mapping of Controller functions to filter functions that are run before them when dispatched to from a route. These are usually used to run pre-processing functions like authentication before a certain function is executed. They are only called when dispatching from a route. Example usage:
Ext.define('MyApp.controller.Products', {
config: {
before: {
editProduct: 'authenticate'
},
routes: {
'product/edit/:id': 'editProduct'
}
},
//this is not directly because our before filter is called first
editProduct: function() {
//... performs the product editing logic
},
//this is run before editProduct
authenticate: function(action) {
MyApp.authenticate({
success: function() {
action.resume();
},
failure: function() {
Ext.Msg.alert('Not Logged In', "You can't do that, you're not logged in");
}
});
}
});
http://docs.sencha.com/touch/2.3.1/#!/api/Ext.app.Controller-cfg-before
Of course, it's still up to you to decide whether you should check every time or should cache the auth result for sometime.
Updated to answer comment below
Honestly, i am not sure how they was going to declare that static method Authenticate in Sencha (you would be able to do it normally through Javascript i think, i.e.: prototype).
But there are other better options to solve just that Authenticate function:
Just create a singleton class that handle utility stuffs.
http://docs.sencha.com/touch/2.3.1/#!/api/Ext.Class-cfg-singleton
If you really want to use MyApp, you can declare within the Ext.app.Application (in app.js). Then call it from the global instance MyApp.app.some_function(). I wouldn't exactly recommend this method because you change app.js, that might bring problem if you upgrade sencha touch.
You could implemented auth check in application's launch function or in your auth controller's init function and based on the response redirect the to appropriate url. Something like this:
TestApp.model.CheckAuthModel.load(1, {
scope: this,
success: function(record) {
this.redirectTo("home/");
},
failure: function() {
this.redirectTo("login/");
console.log('failure');
},
callback: function(record) {
console.log('callback');
console.log();
}
});

Creating a preference through PreferenceManager

SDK 2.0 PreferenceManager, how do I create and update a preference using PreferenceManager? Just using update method does not seem to store the value, and create is "not a function" error. TypeError: Rally.data.PreferenceManager.create is not a function.
//load app preferences
Rally.data.PreferenceManager.load({
appID: this.myAppId,
filterByUser: true,
success: function(prefs) {
//process prefs
if(prefs.releases) {
this.releaseNames = prefs.releases;
} else {
//first time, nothing to load so create the app preferences
Rally.data.PreferenceManager.create({
appID: this.myAppId,
filterByUser: true,
settings: {
releases: ""
},
success: function(updatedRecords, notUpdatedRecords) {
//yay!
debugger;
}
});
}
}
});
//things have changed, save new app preferences
Rally.data.PreferenceManager.update({
appID: this.myAppId,
filterByUser: true,
settings: {
releases: this.releaseNames
},
success: function(updatedRecords, notUpdatedRecords) {
//yay!
debugger;
}
});
I found that the create method is not required, the update method is all that is needed.

Sencha-touch : refresh list : store

I have a list of news in a Ext.List inside a panel
prj.views.NewsList = Ext.extend(Ext.Panel, {
layout: 'card',
initComponent: function() {
this.list = new Ext.List({
itemTpl: '......',
loadingText: false,
store: new Ext.data.Store({
model: 'News',
autoLoad: true,
proxy: {
type: 'ajax',
url: '.....',
reader: {
type: 'json',
//root: ''
}
},
listeners: {
load: { fn: this.initializeData, scope: this }
}
})
});
this.list.on('render', function(){
this.list.store.load();
this.list.el.mask('<span class="top"></span><span class="right"></span><span class="bottom"></span><span class="left"></span>', 'x-spinner', false);
}, this);
this.listpanel = new Ext.Panel({
items: this.list,
layout: 'fit',
listeners: {
activate: { fn: function(){
this.list.getSelectionModel().deselectAll();
Ext.repaint();
}, scope: this }
}
})
this.items = this.listpanel;
prj.views.NewsList.superclass.initComponent.call(this);
},
});
Ext.reg('newsList', prj.views.NewsList);
In a toolbar setup in a dockedItem, I have a icon to refresh the list.
items: [
{
iconCls: 'refresh',
handler: function() {
prj.view.NewsList.list.store.read()
}
},
]
but prj.view.NewsList return undefined! How can I get the list to do a refresh of the store?
Call this line on your refresh button
Ext.StoreMgr.get('newsStore').load()
The list is automaticaly refresh when you call the load() method on the store. The store is linked to the list.
Example:
items: [
{
iconCls: 'refresh',
handler: function(event, btn) {
Ext.StoreMgr.get('newsStore').load();
}
},
]
Even I faced a similar problem.
I am posting my answer hope this helps someone.
I have a search bar in to search data. (my search is taking place at server and the results are sent back to me in response to my GET request.
Basically I just had to change the URL for my store
WHAT ALL I TRIED:
myList.refresh(),
myStore.load();
clearing the store and then loading it
removing the list and adding it again and forcing it to re render (using doLayout())
Nothing worked...
just adding SINGLE line fixed my problem
function handleSearch(strSearchText)
{
//myStore.loadData([],false); /tried to clear the store and reloading it
if(strSearchText !='')
{
searchString = '?search='+strSearchText;
searchURL = searchURLBasic+ searchString;
}else{
searchURL = searchURLBasic;
}
console.log('search URL: ' + searchURL);
myStore.proxy.url =searchURL; // this was one magical line of code that saved my life
myStore.load();
}
THanks SO for support.
I do this when changing the store and it works like a champ
var yourbutton = new Ext.Panel({
listeners: {
afterrender: function(c){
c.el.on('click', function(){
YourList.update();
YourList.bindStore(newStore);
});
}
}
});