How do I re-use components in ExtJS? - javascript

I have an ExtJS grid like so:
var grid = new Ext.grid.GridPanel({
...
});
I'd like to be able to re-use this grid so that I can have it multiple instances of it that all act independently. Is the only way to do this is by using Ext.extend, or is there another way? I don't really need to extend it, I just need to be able to create multiple instances of it.

If you really just need two grid instances, then create another one as Upper Stage said.
If you need to share a config among multiple grids, you could save the config as a separate JS object that you then pass into the grid constructor each time you create one.
var myCfg = { ... };
var grid1 = new Ext.GridPanel(Ext.apply(myCfg, { /* other options */ }));
var grid2 = new Ext.GridPanel(Ext.apply(myCfg, { /* other options */ }));
If you are going to reuse the grid with a particular configuration across your app or in multiple apps, then a subclass may be the best way to go.
This tutorial reviews several different methods for reusing functionality and would be a good starting point for you to decide what approach best suits your needs (if you need something beyond two basic instances).

Ext.Component#cloneConfig() perhaps?

Can you simply instantiate new objects?
var anotherGrid = new Ext.grid.GridPanel({
...
});

Ext has decent support for subclassing. This means you can extend the standard grid and instantiate that:
Foo = {};
Foo.BarGrid = function(config) {
Foo.BarGrid.superclass.constructor.call(this, config); //call the default grid constructor
}
Ext.extend(Foo.BarGrid, Ext.grid.GridPanel, {
//grid config
});
var grid = new Foo.BarGrid({/*minimal config*/});
You can even register your own xtype and use that instead of newing it:
Ext.reg('foobargrid', Foo.BarGrid);
var pane = new Ext.TabPanel({
items: [{xtype: 'foobargrid'}]
});
EDIT Misread the question. Since you obviously know about Ext.extend sharing the config, as suggested by bmoeskau, might just do the trick for you.

Related

One view for 2 or more pages (backbone.js)

I have two pages. One of them is dashboard with a lot of functionality. The second page is shared dashboard - the simple version of the first page.
The dashboard contains the view of the database (it can contain much other info, but the problem with this one). You can click on the filter button and modal window will be opened. So, simple version of the dashboard doesn't have this possibility. I'd like to add it, but I don't want to copy+past code from the full version of the dashboard because the code of this part is about two thousand lines. I'll add some primitive code example:
DashboardView = SomeAnotherView.extend({
initialize: function() {...},
events: {...} // huge objects of jQuery events,
render: function () {...},
... // 2k lines of functions for events
});
How can I use this View on another page? I tried to call a function from this view:
DashboardView.prototype.filterClicked(event);
But in this case event.curentTarget is null (it is necessary for this function), I also tried to send "this" to get the context, but it was failed.
Is there a possibility in Backbone.js to use one View for 2+ pages without any huge copy/past code?
Ideally if you have a simple version and full version of a view, you should have a "base view" (simple one) and the full version should extend the base view.
It'll look something like:
var SimpleDashbard = Backbone.view.extend({});
var Dashboard = SimpleDashbard.extend({});
In this way Dashboard will have access to the methods from SimpleDashbard.
Your situation sounds like you need to use a method from extended view in base view. Which is not a good idea. Ideally if it's shared you should move it to the base view/extract it into a utility method or service, and of course this involve re-writing this method to be reusable
If you have views that share a large amount of functionality, you could consider using the same View type, but opening it up to some configuration when instancing. For example:
var DashboardView = Backbone.View.extend({
initialize: function(options) {
this.allowFunctionX = (options && options.allowFunctionX);
this.allowFunctionY = (options && options.allowFunctionY);
},
// etc
functionX: function() {
if (!this.allowFunctionX) { return; }
// do the function...
},
functionY: function() {
if (!this.allowFunctionY) { return; }
// do the function...
},
});
Then on one page:
var firstDashView = new DashboardView({allowFunctionX: true});
and on another page:
var secondDashView = new DashboardView({allowFunctionY: true});
This may become not worth it if the functionality diverges too much (and there are likely better ways to configure than passing in a long list of booleans!). If your requirements are significantly different on your two pages, I feel like duplicating the code they both need is not a major sin.

Toggle between multiple THREE.EffectComposer scenes using the same renderer in three.js

I am in the process of creating complex scenes with Composer in three.js.
I am wanting to know if it is possible to switch between two scenes that have different composer effects attributed to them. To gain some sort of perspective I have created an example which allows you to toggle between two normally rendered scenes.
Two scene example
From my understanding of how composer works you create an instance of it and then apply a render pass like so:
this.composer = new THREE.EffectComposer(this.renderer.default.init);
this.renderPass = new THREE.RenderPass(this.stage, this.camera);
this.renderPass.renderToScreen = true;
this.composer.addPass(this.renderPass);
and then apply a composer render like so:
this.composer.render();
So my question is if I have a second scene which a composer instance how can I then:
Use the same renderer (if possible)
Toggle between scene 1 and scene 2 like in a similar fashion to my example.
You can just switch from one effectComposer to another one the same way as you switch from one scene to the other. So that would be something like this:
const scenes = [
new THREE.Scene(),
new THREE.Scene()
];
const composers = scenes.map(function(scene) {
const composer = new THREE.EffectComposer(renderer);
// configure render-passes
const renderpass = new THREE.RenderPass(scene, camera);
renderpass.renderToScreen = true;
composer.addPass(renderpass);
scene.composer = composer;
return composer;
});
// then use the composer for the scene
let activeScene = scenes[0];
activeScene.composer.render();
You should even be able to reuse certain render-passes if you want to.
So before I begin I just want to give a shout out to Martin Schuhfuß who provided the insight to this solution.
Disclaimer
I am not an expert or professional Programmer in javascript and I by no means suggest that this is the only way of doing this, my presentation should be taken in an abstract fashion. My thoughts only explain the theoretical premises for which the solution is based on and implementation of this will depend upon your own architecture.
Architecture
I am using an OOP method in this example, you should be able to manipulate the solution to whatever method you are using.
Method
So based on Martin’s current example you can see that we able to add the composer property/object to our scene object this means that scenes could inherit the same composer effects which is brilliant, however In my case I have many scenes with different composer effects so I needed to rethink the problem.
1. Create a Composer object.
So I created an object to put composer objects in and keep to the nice ‘composer’ name convention when reference my effects.
This.composer = {};
2. Create a function to initialise RenderPasses with the concerning scenes.
So it is important to remember that we need to define and initailse the RenderPasses first before will call our composer. RenderPasses allows us to attribute the effects (know has shaders) that we want. In my example I have two scenes therefore I needed to create:
Two RenderPasses.
One RenderPass copied the scene.
The other RenderPass applied a sepia effect to its scene.
Example of Code:
this.init = function() {
stackoverflow.webgl.pass.base = new THREE.RenderPass(stackoverflow.webgl.scene.default,
stackoverflow.webgl.camera);
stackoverflow.webgl.pass.base2 = new THREE.RenderPass(stackoverflow.webgl.scene.test,
stackoverflow.webgl.camera);
stackoverflow.webgl.pass.sepia = new
THREE.ShaderPass(THREE.SepiaShader);
stackoverflow.webgl.pass.sepia.renderToScreen = true;
stackoverflow.webgl.pass.copy = new THREE.ShaderPass(THREE.CopyShader);
stackoverflow.webgl.pass.copy.renderToScreen = true;
}
Note: some file names had to be renamed due to legal reason, but the point being is that this function is called into a larger object.
3. Create a start function and lets assign composers to scenes
The purpose of this function is just to demonstrate how we combine it all together. So the code that we have is something like this.
// so we create an object to use for reference for EffectComposer objects
this.composer = {};
// this property is used to set the scene that we want
// this.scene.default = new THREE.Scene();
this.activeScene = this.scene.default;
// this function is just a wrapper for our code
this.start = function () {
// so call our initialise our RenderPasses
stackoverflow.webgl.pass.init();
// my own method of seting up the WebGLRenderer scene (You do it your Way!)
stackoverflow.webgl.renderer.default.setup;
// Create a new composer for scene 1
this.composer.ui = new THREE.EffectComposer(stackoverflow.webgl.renderer.default.init);
// Create a new composer for scene 1
this.composer.ui2 = new THREE.EffectComposer(stackoverflow.webgl.renderer.default.init);
// Now here is the cool stuff you can assign a composer to each scene
this.scene.default.composer = stackoverflow.webgl.composer.ui;
this.scene.test.composer = stackoverflow.webgl.composer.ui2;
// and i always like to check that things happen and they do ;)
console.log(this.scene.default);
console.log(this.scene.test);
console.log(this.composer);
// so you will need to add the passes some place, I created a function call render, (you do according to your code structure)
stackoverflow.webgl.render();
}
4. Define where you add the passes in your architecture
So now we will need to add the pass declarations (addpass functions from composer) for our effects to take place.
this.render = function () {
stackoverflow.webgl.composer.ui.addPass(stackoverflow.webgl.pass.base);
stackoverflow.webgl.composer.ui.addPass(stackoverflow.webgl.pass.copy);
stackoverflow.webgl.composer.ui2.addPass(stackoverflow.webgl.pass.base2);
stackoverflow.webgl.composer.ui2.addPass(stackoverflow.webgl.pass.sepia);
};
5. Add the EffectComposer render method
So this line of code will need to be placed wherever you do the composer processing (that depends on your setup).
stackoverflow.webgl.activeScene.composer.render();
Please take note that the ‘activecScene’ part makes reference to the actual scene used at the time. It is this that allows us to change the scene.
6. Create a button and toggle between the scenes
So I created two buttons in a dat.gui instance that allows me to toggle between the two scenes.
Again you can create a button, function whatever you like.
// again just change the vale of active scene to the scene you wish to change to
// button 1 value will be something like this:
stackoverflow.webgl.activeScene = stackoverflow.webgl.scene.test;
// button 2 value will takes us back to scene 1
stackoverflow.webgl.activeScene = stackoverflow.webgl.scene.default;
Conclusion
This is my method of achieving this effect, but if there are better or alternative ways then please add to the discussion and share.

Separating Knockout.js, Node.js, and Standalone API but maintain two bindings and other functionalities

I've given myself an exercise to understand how one could write a scalable API independently of an MV* framework to be used in non-DOM environment. The desirable end result would be to have a class library or sorts, that is then in turn utilized by MV* framework such as Knockout, which I use in the example below.
The biggest challenge I've found so far is to dealing with retaining two-way bindings. In order to do this, the underlying properties are required to be observable.
// no DOM in here, just the basics
function QueryRequest(){
};
QueryRequest.prototype = {
get preference() {
return this._preference;
},
set preference(val) {
this._preference = val;
}
}
Here is an example of what a function definition would look like from the library.
function QueryRequestViewModel() {
QueryRequest.call(this);
// DOM interaction safe in here...
this.preference = ko.observable('Pizza');
};
// inherit from QueryRequest, then point the constructor back to the view model, base we already call base.
QueryRequestViewModel.prototype = new QueryRequest();
QueryRequestViewModel.prototype.constructor = QueryRequestViewModel;
ko.applyBindings(new QueryRequestViewModel()); // bind
Here is the view model, which is not independent but would inherit from QueryRequest.
<input id="user-desire" type="text" name="desire" maxlength="500" data-bind="value: preference" />
Everything almost works but there's a tad annoying issue.
When knockout goes to set the variable, it is not setting just the primitive, it wants to set it's own object back. Obviously, this is not the desired outcome.
My only requirement is that knockout and any DOM-related code can not be in the library.
Is there another way of achieving what I want? I'm open to the of another MV* library which takes a different approach at observing attributes as well.
Is this what you are trying to acheive? I've adapted your code into a JSFiddle here http://jsfiddle.net/rwisch45/6Lkv3/3/
Just some basic view model inheritance. Since I am setting preference as an observable in the base view model, it is accessible in view models that inherit that base.
// no DOM in here, just the basics
var QueryRequest = function () {
var self = this;
self.preference = ko.observable();
}
function QueryRequestViewModel() {
var self = this;
// inherit from QueryRequest, then point the constructor back to the view model, base we already call base.
QueryRequest.call(self);
self.setPreference = function () {
self.preference("Pizza");
}
};
ko.applyBindings(new QueryRequestViewModel());
And you could pass options to a base view model like this, http://jsfiddle.net/rwisch45/6Lkv3/4/

set the data to dojo data grid

I am working with Dojo, and I have a small requirement. I am using a store to create a Memory. I have a hardcoded list so that I can set this list to a Dojo data grid store and thereby perform some rowclick functions. My issue is that I am not able to set the store, and I am getting an error,
this.headerContentNode.firstChild is null. Please can anybody help me out?
the code snippet....
postCreate : function () {
//publist, sublist etc
this._handleLogDetails();
},
//methods...
_handleLogDetails : function(){
alert("hello...h..");
var theGreatestTeamOfAllTime = [ {
"jobName":"12",
"jobId":"Jim Kelly",
"status":"QB",
"timeStamp":"0"
},
{
"jobName":"1",
"jobId":" Kelly",
"status":"B",
"timeStamp":"10"
}
];
var clientJobStore = this.jobModel.getLogStore();
clientJobStore.setData(theGreatestTeamOfAllTime);
var thisData = new ObjectStore({objectStore: clientJobStore});
this.dapJobStatusGrid1.setStore(thisData); // attach point of dojo data grid, getting an error at this point...
Hard to say exactly what the issue is here without seeing how the grid is configured, but this is likely caused by one of the following:
You didn't call startup() on your grid.
When constructing your grid, you did not provide a DOM node for the grid.
For example, perhaps try something like the following, where the second argument is the DOM node the grid should be attached to.
var options = {// some options};
var foo = new DataGrid(options, someContainer.domNode);
foo.startup();

Dojo widget defaults

i'm currently writing a large scale application heavily based on the dojo toolkit. The whole app is working and standing, but one issue i can not find my way out with, is the creation of custom widgets. It would be useful because it would clean up my source code and also i can reuse this 'widgets' in later projects.
For example: i have a main toolbar, which i would like to call using
myapp.toolbar = new myapp.mainToolbar();
instead of using
myapp.toolbar = new new dijit.Toolbar({}, containerID);
var button1 = new dijit.form.Button({
label: 'Delete',
id: 'toolbarbutton1',
showLabel: true,
iconClass: "dijitEditorIcon dijitEditorIcon Delete"
});
myapp.toolbar.addChild(button1);
...
So in short: how do i set up the whole toolbar somewhere else and call it as a simple object? Trying to figure out dojo.declare('myapp.mainToolbar', dijit.Toolbar, {...}) but then i get a bunch of errors like 'startup function not existing' etc...
I'd like to do all this programmatically, so without the template html and css files in a custom widget.
A link to a good tutorial or howto would be nice, although google nor yahoo! will reveal any extra's on this matter for me... :)
There are multiple ways to do this.
It seems like your method of extending Toolbar should work (not sure why it didn't).
You can also declare a class that embeds Toolbar and the buttons, using widgetsInTemplate:
dojo.declare("MyToolbar", [dijit._Widget, dijit._Templated], {
_widgetsInTemplate: true,
templateString: '<div> <div dojoType=dijit.Toolbar>' +
' <button dojoType=dijit.form.Button ...
Note that the top node in MyToolbar can't have a dojoType, so I put Toolbar one level down.
Alternately you can do the same thing by using dijit.Declaration, see http://docs.dojocampus.org/dijit/Declaration.
It works for me when I use declare with the superclass inside of an array:
dojo.declare('myapp.mainToolbar', [ dijit.Toolbar ],
{
....
}
);
var x = new myapp.mainToolbar({ ... });
x.startup();
Which kind of violates the docs. It should take one Function or an array of Functions.

Categories

Resources