I have a web app for which I am using ExtJS 4.2. This application has a bunch of different components - a panel that displays some data, another panel that displays some other data, a grid, a chart, etc, etc.
It's required that each component has at minimum a specific set of functions and properties. So I'd like to define a 'component' class that I can extend everything else from. For example:
Ext.define('MyApp.BaseComponent', {
extend: 'Ext.panel.Panel',
alias: 'widget.myapp-basecomponent',
prop1: true,
prop2: 17,
func1: function (a, b) {
return a + b;
}
});
Then I would extend every individual component in my app from that base component class. The problem is that if I define the base component as extending 'Ext.panel.Panel', I can only extend other panels from it. I can't extend a grid, tree, etc, etc from it.
Is there a way I can accomplish this? Or am I approaching this the wrong way? Maybe I should just nest everything that's not a panel (grid, chart, etc) in a panel so they can all extend from BaseComponent? Advice greatly appreciated.
If you just want to augment the base component class, you could always just provide an override that adds them:
Ext.define('MyApp.AugmentComponent', {
override: 'Ext.Component',
a: 1,
b: 2,
fn1: function() {
}
});
Related
The code below is from FullCalendar's Custom View documentation. It seems like a great start, but it would be very helpful for someone brand new like me to have some basic code that renders the most simple custom view (with some events). They tell you to look at BasicView and AgendaView as a reference, but it's a little beyond my understanding. Are each of the functions required to be overridden in the custom class?
This Plunker has a basic FullCalendar and a button to change to a custom view. What would be very helpful is to see a working example. I have been tinkering for hours with no success for a custom view. If you know FullCalendar and would be willing to fill in some code for the functions it would be very appreciated!
https://plnkr.co/edit/gfEUCVYTWTm1md24e33m?p=preview
My goal is to build a day list that lists all events of the day in order in a scrollable div (where each entry will eventually be quite fleshed out with data and css styling--I'm not sure if listDay would allow for this type of customization??).
var FC = $.fullCalendar; // a reference to FullCalendar's root namespace
var View = FC.View; // the class that all views must inherit from
var CustomView; // our subclass
CustomView = View.extend({ // make a subclass of View
initialize: function() {
// called once when the view is instantiated, when the user switches to the view.
// initialize member variables or do other setup tasks.
},
render: function() {
// responsible for displaying the skeleton of the view within the already-defined
// this.el, a jQuery element.
},
setHeight: function(height, isAuto) {
// responsible for adjusting the pixel-height of the view. if isAuto is true, the
// view may be its natural height, and `height` becomes merely a suggestion.
},
renderEvents: function(events) {
// reponsible for rendering the given Event Objects
},
destroyEvents: function() {
// responsible for undoing everything in renderEvents
},
renderSelection: function(range) {
// accepts a {start,end} object made of Moments, and must render the selection
},
destroySelection: function() {
// responsible for undoing everything in renderSelection
}
});
I've added a few lines to your plunker to make the custom view work. You can find here the example: https://plnkr.co/edit/8iOq15CsL2x6RPt29wgE?p=preview
Just to mention the changes:
In the calendar initializer the view definition has been added
$('#calendar').fullCalendar({
...
views: {
CustomView: {
type: 'custom',
buttonText: 'my Custom View',
click: $('#calendar').fullCalendar('changeView', 'CustomView')
}
}
});
In the custom view just added this in the render
$('.fc-view').append("<div>Insert your content here</div").css("background", "red");
In the custom view you get access to the events by doing this:
var myEvents=$('#calendar').fullCalendar('clientEvents');
From there on you can do your further customizations
I want to create a custom component(container) that would contain other components (labels, buttons,...).
I would like to create some kind of a class so I would be able to create multiple instances of this component but with different params. Somekind of constructor. These params would set the labels and button options.
I am using Sencha Architect, so I am wondering is this possible and how it could be done?
Via ExtJS code you just can use the Ext Class System:
Ext.define('MyOwnView', {
extend: 'Ext.container.Container',
constructor: function () {
// ... your code
}
});
To achieve this via Architect GUI, follow this guide (with screenshots):
http://docs.sencha.com/architect/3/creating_an_application/working_with_classes.html
You can use Ext.define (http://docs.sencha.com/extjs/4.2.2/#!/api/Ext-method-define) to define your new class prototype as follows:
Ext.define('My.app.Panel', {
extend: 'Ext.panel.Panel',
requires: [
'My.app.PanelPart2',
'My.app.PanelPart3'
]
constructor: function (config) {
this.callParent(arguments); // calls Ext.panel.Panel's constructor
//...
}
});
I am trying to solve a problem with a functionality I need to implement for a grid. This grid should use a custom "filter" which extends from "Ext.ux.grid.FiltersFeature", this component works fine since it works for other grids I implemented. the problem is that the grid I want to implement now, does not load it columns at the first moment like the previous I implemented; this grid has a controller which uses a "reconfigure" method to create the columns based on a "store".
For instance:
grid.reconfigure(store, cols);
I've seen many examples on how to add individual filters and so on, but they use the "ftype: "filters", I do need to use my "ftype: mycustomfilter" specifically. Any idea on how can I do this? I tried everything, but nothing seems to be working and I am stucked with this.
Here's some of my code:
Portion of code in the Controller:
if (refreshGrid) {
var cols = this.createGridColumns();
//This is the method that loads my column based on the store
//(which I retrieve from Ajax request)
grid.reconfigure(store, cols);
oldStore.destroyStore();
} else {
this.mergeFn.call(this, values, store);
grid.view.refresh();
}
What I tried to do is to add a feature after reconfiguring the grid:
grid.reconfigure(store, cols);
//Then I add this portion of code:
grid.features = [{
ftype: 'customfilterfeature',
autoReload: false,
local: true,
filters: [{type: 'list', dataIndex: 'activity'},
{type: 'list', dataIndex: 'datetime'}]
}]
Does anybody have an idea on how can I achieve this? Because this is not working at all, the filter is not being displayed. Any help will be really appreciated. Thanks in advance.
We had to do this on several grids.
We extended from Ext.ux.grid.filter.Filter and then used these filters on the column basis, not the grid itself. This way, each column could specify the filter they want, which would be changed everytime you reconfigure your grid.
Just require your filter class extension in your controller, and you can use it this way:
var columnsDef: [
{ text: 'Column Name', dataIndex:'foo', filter: { type: 'yourCustomFilterAlias'}},
...
];
grid.reconfigure(store, columnsDef);
After that it is just a matter of overriding the right methods in your custom Filter class.
Hope this helps.
I've spent a lot of time debugging strage error in my component. That component have disabled/enabled buttons, but I haven't seen the effect. After a while, I've noticed, the buttons are changed in the last component instance I've created. The declaration looks so:
constructor: function(options) {
for(var i in options){
this[i] = options[i];
}
},
domNode: null,
grid: null,
data: [],
buttons: {},
In the debug, I've seen, that when I create second instance of my object:
new CustomComponent({domNode: dojo.byId('secondid')})
the buttons are already set - their instance is shared by all instances!
In end effect, I've created a static variable in my component. This is not what I wanted! What is wrong in that declaration? How should I made 'buttons' instance separate for each component instance?
I suppose that CustomComponent is a widget? Then you're doing some stuff wrong. The thing you do in your constructor (I suppose that's to populate your widget properties?) is not even necessary since that's already there by default when you use dijit/_WidgetBase.
Same with your property domNode, it's also there already by default if you use dijit/_WidgetBase.
My guess is that by overriding the constructor to act like this, you're actually doing some steps that the WidgetBase should do and thus messing up the private scope of the properties.
An example widget:
var CustomComponent = declare("my/CustomComponent", [WidgetBase], {
grid: null,
data: [],
buttons: {}
});
This code does exactly the same as your widget and is a lot shorter.
An example JSFiddle that has instance scoped properties (as you can see in the console log).
I've inspected the problem more exact. The problem is, that the declare block is executed only once, therefore creating object prototype, which values are copied to instances.
So when I do buttons: {}, I create Object, which is then copied to all children. In end effect, all children have the same buttons instance - I've created a quasi-static field.
All bugs where gone when I've created the object in the constructor:
constructor: function(options) {
for(var i in options){
this[i] = options[i];
}
this.buttons = {}
this.data = []
},
Now every instance of my component have own buttons object.
In fact, my problem was exactly described here:
dojo.declare("my.classes.bar", my.classes.foo, {
someData: [1, 2, 3, 4], // doesn't do what I want: ends up being
I'm trying to find best option to make Backbone views reusable. I goggled and found many different solutions but not sure which one suits my requirements. Basically I'm going to have many widgets filled with real time data and I need a base component that will handle service subscriptions
Is following best solution for this problem:
App.View.Base = Backbone.View.extend({
baseMethod: function( params ) {};
});
App.ExtendedView.Base = App.View.Base.extend({
// new stuff here
// overriding App.View.Base.baseMethod
baseMethod: function( params ) {
// overriding stuff here
App.View.Base.prototype.baseMethod.call(this, params); // calling super.baseMethod()
}
});
Is there any better approach? or should I use mixins?
I might be inclined to favour composition over inheritance here, and create a spinner view, and use instances of it in other views that require spinner functionality.
More info: Prefer composition over inheritance?
The typical rule-of-thumb I use for stuff like this is if there are any immutable methods in the base class that provide a common context for all your sub-classes, then inheritance makes sense. For instance, I've created a BaseView class for my Backbone application that looks something like this:
define(function() {
return Backbone.View.extend({
/**
* show() and hide() are immutable
*/
show : function() {
this.beforeShow();
this.doShow();
this.afterShow();
},
hide : function() {
this.beforeHide();
this.doHide();
this.afterHide();
},
doShow : function() {
this.$el.show();
this.trigger('displayComplete', {action : 'show'});
},
doHide : function() {
this.$el.hide();
},
//Override the following to extend behavior of the view
//before and/or after the view is shown/hidden.
beforeShow : function() {},
beforeHide : function() {},
afterShow : function() {},
afterHide : function() {}
});
});
This is a pretty simple example, but it has proven to make things much easier for development of my application, as my central controller object is given a common interface for showing and hiding views. I suppose you could use composition here as well, but that requires doing an explicit extend() at runtime. You get the same result in either case, but I just prefer to have the functionality available when I instantiate my views.
Another thought is that it really depends upon what you want to accomplish. Inheritance is much more rigid than composition, but again, it depends upon what you ultimately want to accomplish, and sometimes enforcing rigidity to maintain a context is a good thing.