I have three different areas in my application that can modify hours. They all use the same grid, store, and model (but different instances) and call the same backend controller. I am trying to implement a way to add a parameter to the AJAX calls, so the backend knows which area of the application that the call came from through the use of a parameter to AJAX calls.
I have attempted the following:
(1) Overriding request function in Ext.data.Connection
Ext.data.Connection.override({
request: function(options){
var me = this;
if(!options.params)
options.params = {};
options.params.location = 'location 1';
return me.callOverridden(arguments);
}});
Result: I couldn't figure out a way to find the module that made the call.
(2) Adding the following to the controllers init of the controllers
Ext.Ajax.on('beforerequest', function(conn, options) {
if(!options.params)
options.params = {};
options.params.location = "location 1";
});
Result: Every call was sending the same location even if it was a different area
Considering that you are using the same store but different instances, the easiest way is to use the store methods of synchronization only. You would have to define the proxy on the store, not the model, then you can easily add a special extraParam on every instance:
Ext.define('MyStore', {
extend: 'Ext.data.Store',
proxy: {
type: 'ajax'
url: 'test.json'
}
});
var instance1 = Ext.create('MyStore');
var instance2 = Ext.create('MyStore');
var instance3 = Ext.create('MyStore');
instance1.getProxy().setExtraParam('source', 'instance1');
instance2.getProxy().setExtraParam('source', 'instance2');
instance3.getProxy().setExtraParam('source', 'instance3');
instance1.load();
instance2.load();
instance3.load();
and to sync:
instance1.getAt(0).set('text', 'testinstance1');
instance2.getAt(0).set('text', 'testinstance2');
instance3.getAt(0).set('text', 'testinstance3');
instance1.sync();
instance2.sync();
instance3.sync();
See in action here: https://fiddle.sencha.com/#view/editor&fiddle/2fl4
Open the network tab to see the parameter:
Related
In my controller I want to use certain variables in several places.
For example I got a form with few fields (combo / textfield) and I want to use a link to them in a various places of my controller code. How can / should I declare such variable?
Usually I use:
refs: [
{
ref: 'myCombo',
selector: 'myPanel combo[name=myCombo]'
},
{
ref: 'myTextfield',
selector: 'myPanel textfield[name=myTextfield]'
}
]
But is it ok to use getMyCombo() / getMyTextfield() every time I have to work with this fields in my controller?
The "refs" feature of the controller is really just generating getter functions for you by using Ext.ComponentQuery with the provided CSS selector. The way you're using them is one way you can make use of the system, though you can also use refs to instantiate (for example) views for the controller using their configured alias or xtype. In your example, you're saving yourself the hassle of re-writing some long-ish ComponentQuery calls.
The 'autoCreate' option, although not documented, is great for this type of thing if for example you wanted to always instantiate a new instance of a certain object every time the controller is activated, you could do so in the init() function.
The answer posted here demonstrates using refs to create new instances and further explains the functionality of autoCreate and forceCreate options.
If you want to use an object or some variable throughout your controller, just set a property on the controller, most suitably in the init method...
Ext.define('App.controller.Messaging', {
/** Include models, stores, views, etc... */
refs: [{
ref: 'messageBox', // creates magic method "getMessageBox"
xtype: 'my-messagebox', // in the class file: alias: 'widget.my-messagebox'
selector: '', // could be itemId, name, etc. Same rules as a CSS selector
autoCreate: true // automatically create when "getMessageBox()" is called
}],
/** I always initialize controllers as-needed, passing the application object */
init: function(app){
var me = this;
// Initialize whatever you need, maybe set up some controller properties
this.eventBus = app.getEventBus();
this.user = app.getActiveUser();
// I prevent listeners from being established twice like this..
if(this.inited === true)
return;
this.inited = true; // nothing past this line will be executed twice
// Observe view events
this.control();
// Listen for application events
app.on({
'getMessages': {fn: me.showMessageBox, scope: me}
});
// Specific controller events
this.on({
'someEvent': {fn: me.someFunction, scope: me}
});
},
// A function using controller properties defined in the init() method
someFunction = function(){
var me = this; // controller
// Lets show the active user
console.warn("Active User", me.user);
// And then fire an event, passing this controller
me.eventBus.fireEvent('somethingHappened', me);
},
// Invoked on the application event "getMessages"
showMessageBox: function(sessionId){
var me = this; // controller
/** ... Load the messages for the provided sessionId ... */
// Then create an instance of the message box widget as property on the controller
me.messageBox = me.getMessageBox({
/** pass config to the view here if needed */
});
}
});
I am using backbone.marionette (1.0.0) and node.js (0.10.22). Wondering why backbone add extra parameter when I try to save model data with node.js REST call.
model.js
Backbone.Model.extend ({
urlRoot: function (){
return '/path/' + myApp.companyId;
},
defaults: {
companyId: '',
// other attributes
},
// doesn't use 'id' in model instead companyId
idAttribute: 'companyId'
});
Before view is loaded, I would request model data with myApp.request ('entities:myModel') which issued model.fetch () and node.js backend would fire GET /path/1 route. No issue.
However, when an update button is clicked on the view, this.model.save () would fired PUT /path/1/1. It should be PUT /path/1, with only a single '1' in url path.
view.js:
clicked: function () {
var formData = Backbone.syphon.serialize (this);
this.model.set (formData);
var promise = this.model.save ();
promise.done ().fail ()
}
How can I stop backbone.sync from appending extra parameter to url path? Thanks for taking time out to read this, and I appreciate your help.
You're setting urlRoot incorrectly on the model. It should be
Backbone.Model.extend ({
urlRoot: "path",
// etc
});
Backbone willa dd the ids on it's own.
If you want to specify the ids in your function, use the url function.
I am using backbone-relational. The usage for a onetomany model works fine.
But I am having troubles using backbone-relational for a single/standalone model:
window.BeerOnlineShopPosition = Backbone.RelationalModel.extend({
urlRoot:"../api/beeronlineshoppositions",
idAttribute: 'id',
relations: [
],
defaults:{
"id":null,
"position_amount":""
}
});
window.BeerOnlineShopPositionCollection = Backbone.Collection.extend({
model:BeerOnlineShopPosition,
url:"../api/beeronlineshoppositions"
});
in main i have:
beeronlineshopproductDetails:function (id) {
var beeronlineshopproduct = BeerOnlineShopProduct.findOrCreate(id);
beeronlineshopproduct.fetch();
var beeronlineshopproduct_view = new BeerOnlineShopProductView({el: $('#content'), model: beeronlineshopproduct});
},
So, when jump to an existing records (...beeronlineshop/beeronlineshopproducts/#4), nothing happens. But debugging shows, that the fetch is executed and the view gets loaded. but the view is not rendered somehow.
When I refresh (f5), the view gets rendered correctly.
As mentioned the whole thing works for one-to-many model, so my question is:
did i make some trivial syntax-error on the model part?... or is there any other obvious reason for the troubles i have?
It may be because of the asynchronous request created by findOrCreate. beeronlineshopproduct.fetch() is making a request to the server but the view is being rendered before the server returns with a response.
You have two options. You can pass in the rendering of the view as a callback upon fetch's success like so:
beeronlineshop.fetch({
success: function() {
var beeronlineshopproduct_view = new BeerOnlineShopProductView({el: $('#content'), model: beeronlineshopproduct})
});
Or you can pass an initializer in your BeerOnlineShopProductView that listens to the its model syncing with the server, and calls for the view to re-render itself, like so:
window.BeerOnlineShopProductView = Backbone.View.extend({
initialize: function() {
this.listenTo (this.model, "sync", this.render)
},
})
I'm building some JS to access Google places JS API using backbone. So far I'm really stuck with the model bindings.
I overrode 'fetch' to be able to use the Google API. The call to Google works just fine.
var Places = Backbone.Collection.extend({
model: Place,
fetch: function(options) {
// SNIPPET //
service = new google.maps.places.PlacesService(map);
service.nearbySearch(request, this.googlePlaceCallback);
// SNIPPET //
},
parse: function(response){
// nerver called
},
googlePlaceCallback: function(results, status) {
// I do something here and is properly called after Google returns a response
}
});
I also defined a very simple View:
var MapView = Backbone.View.extend({
initialize: function() {
this.model = new Places();
this.model.bind("reset", this.render, this);
this.model.fetch();
},
render : function () {
console.log( this.model.toJSON() );
}
});
I can't figure out how to populate the 'model'. Google returns the expected results, but I can set them to the backbone model. I there something I need to do in 'googlePlaceCallback'? I'll probably will need to override 'parse' also since Google results are not quite all interesting.
Assuming that results is a collection of the results you want, you should be able to implement the callback as follows:
googlePlaceCallback: function(results, status) {
this.add(results);
}
Since Places is a backbone Collection, you're just calling the following method in the above code: http://backbonejs.org/#Collection-add
You will also have to get the correct this reference inside the googlePlaceCallback function (you want this to be the Collection). One way to do that is to use Underscores bindAll method ( http://underscorejs.org/#bindAll ), which you can use to make sure all methods in the Backbone class have a this context of the Collection itself. You can do this on initialize as follows:
initialize: function() {
_.bindAll(this);
}
Also, the reason parse is not being called is because you are overriding fetch, and fetch calls parse. If you take a look at the annotated backbone code, you will be able to see the method call: http://backbonejs.org/docs/backbone.html
I need to query the database using a backbone collection. I have no idea how to do this. I assume that I need to set a url somewhere, but I don't know where that is. I apologize that this must be a very basic question, but I took a backbone course on CodeSchool.com and I still don't know where to begin.
This is the code that I have for the collection:
var NewCollection = Backbone.Collection.extend({
//INITIALIZE
initialize: function(){
_.bindAll(this);
// Bind global events
global_event_hub.bind('refresh_collection', this.on_request_refresh_collection);
}
// On refresh collection event
on_request_refresh_collection: function(query_args){
// This is where I am lost. I do not know how to take the "query_args"
// and use them to query the server and refresh the collection <------
}
})
The simple answer is you would define a URL property or function to your Backbone.Collection like so:
initialize: function() {
// Code
},
on_request_refresh_collection: function() {
// Code
},
url: 'myURL/whateverItIs'
OR
url: function() {
return 'moreComplex/' + whateverID + '/orWhatever/' + youWant;
}
After your URL function is defined all you would have to do is run a fetch() on that collection instance and it will use whatever you set your URL to.
EDIT ------- Making Collection Queries
So once you set the URL you can easily make queries using the native fetch() method.
fetch() takes an option called data:{} where you can send to the server your query arguments like so:
userCollection.fetch({
data: {
queryTerms: arrayOfTerms[], // Or whatever you want to send
page: userCollection.page, // Pagination data
length: userCollection.length // How many per page data
// The above are all just examples. You can make up your own data.properties
},
success: function() {
},
error: function() {
}
});
Then on your sever end you'd just want to make sure to get the parameters of your request and voila.