I have a window component which I'm extending to create different windows. Now, the close() and hide() listener functions are the same across board, but the afterrender() changes with each instance.
So I have something like:
Ext.define('abc.xyz.BaseWindow', {
extend : "Ext.Window",
listeners: {
hide: function(el, eOpts){
console.log('hide');
},
close: function(el, eOpts){
console.log('close');
}
}
});
And:
Ext.define('abc.xyz.MyWindow', {
extend : "abc.xyz.BaseWindow",
listeners: {
afterrender: function(el, eOpts){
console.log('afterrender');
}
}
});
However, the whole listeners object is overridden and hide() and close() are never called. Is there any way around this, except to specify hide() and close() in every extended window?
You can define your functions in the window, call them and override them in the window like this:
Ext.define('abc.xyz.BaseWindow', {
extend : "Ext.Window",
onHide: function(){
console.log('hide');
},
onShow: function(el, eOpts){
console.log('close');
},
onAfterRender: function(el, eOpts){
console.log('first after render');
},
initComponent: function () {
var me = this;
Ext.applyIf(me, {
listeners: {
hide: me.onHide,
show: me.onShow
afterrender: me.onAfterRender
}
});
me.callParent(arguments);
}
});
And:
Ext.define('abc.xyz.MyWindow', {
extend : "abc.xyz.BaseWindow",
onAfterRender: function(el, eOpts){
console.log('second after render');
}
});
Or if you don't have an afterrender in the base class you just add a listener with (on) like Evan Trimboli sais
Ext.define('abc.xyz.MyWindow', {
extend : "abc.xyz.BaseWindow",
initComponent: function () {
var me = this;
me.callParent(arguments);
me.on('afterrender', function(el, eOpts){
console.log('second after render');
});
}
});
Related
I am have formula and want execute it when store in this viewModel is changeData.
When I do this, the formula does not work when data in store changed
stores: {
currentStore: {
extend: 'Ext.store.MyStore',
trackRemoved: false
},
},
formulas: {
'executeWhenStoreChange': {
bind: '{currentStore}',
get: function () {
console.log('store change')
},
If you're looking to fire a function when data changed I would use a datachanged listener to the store(s) you want the event to fire on.
currentStore: {
listeners: {
datachanged: function(store, eOpts) {
console.log('store change');
}
}
},
If you want it for all stores just reference the function in each datachanged listener
currentStoreA: {
listeners: {
datachanged: 'onStoreDataChangeD'
}
},
currentStoreB: {
listeners: {
datachanged: 'onStoreDataChangeD'
}
},
Then in the view controller:
onStoreDataChangeD: function(store, eOpts) {
console.log('store changed');
}
In my code I use MVC architecture. My view Component looks like this:
Ext.define('calendar.view.event', {
extend: 'Ext.Component',
alias: 'widget.event',
renderTo: Ext.getBody(),
initComponent:function(){
this.addEvents('eventClick');
this.callParent(arguments);
},
afterRender: function() {
this.mon(this.el, 'click', this.eventClick, this); //mon( item, ename, [fn], [scope], [options] ) - zkratka pro addManagedListener.
this.callParent(arguments);
},
eventClick: function (ev, t) {
var height = this.getHeight();
this.fireEvent('eventClick', this, height, ev);
}
});
Im firing Event on click for controller which is like this:
Ext.define('calendar.controller.eventsChange', {
extend: 'Ext.app.Controller',
views: ['event'],
init: function () {
this.control({
'event': {
eventClick: function (callerObject) {
this.editEvent(callerObject)
}
}
});
},
editEvent: function (callerObject) { //oznaci jako editovatelny
callerObject.get
if(callerObject.hasCls('SpecEv') || callerObject.hasCls('activeEvent'))
{
if (callerObject.hasCls('activeEvent'))
{
callerObject.removeCls('activeEvent');
callerObject.addCls('SpecEv');
this.application.fireEvent('reRender');
}
else
{
console.log(callerObject);
callerObject.addCls('activeEvent');
callerObject.removeCls('SpecEv');
Ext.apply(callerObject, {
resizable: {
pinned:true,
dynamic:true
},
draggable: true,
});
callerObject.setLocalX(0);
var parentWidth = Ext.getCmp('SpecEv').getWidth();
callerObject.setWidth(parentWidth);
}
}
}
});
The problem comes when with
Ext.apply(callerObject, {resizable: {
pinned:true,
dynamic:true
},
draggable: true,
});
When console.log shows me the object after my apply, it says draggable:true and resizable:true. Does anyone know where the problem is?
Thanks for reponses.
It can't works, because your code only set configuration properties, which are handled only when component is initializing. So when you set these properties on already constructed object nothing happen. Component resizability and draggability will not be initialized automatically after setting these properties.
You can try use Ext.Component initResizable and initDraggable methods. But these methods are internal and undocumented.
callerObject.initResizable({
pinned:true,
dynamic:true
});
callerObject.initDraggable();
Also you can try setup Ext.util.ComponentDragger and Ext.resizer.Resizer for your existing component manually.
I define a treepanel. And i try add mask() for waiting tree is loading done. But not working.
Here is my code
Ext.define('Example.example', {
extend: 'Ext.tree.Panel',
alias: 'widget.example',
title: 'example',
store: Ext.create('Ext.data.TreeStore', {
...
listeners: {
'load': function (store, records, success) {
Ext.ComponentQuery.query('example').getEl().unmask(); // not working
},
'beforeload': function (store, options) {
Ext.ComponentQuery.query('example').getEl().mask();// not working
}
}
})
});
How to make that working thank.
EIther use the undocumented ownerTree property:
beforeload: function() {
this.ownerTree.getEl().mask("Loading", 'x-mask-loading');
}
Or register your listeners in a method in order to get the scope:
Ext.define('Example.example', {
// ...
,initComponent: function() {
this.callParent(arguments);
this.getStore().on({
scope: this
,beforeload: function() {
this.getEl().mask("Loading", 'x-mask-loading');
}
});
}
});
try this one Ext.ComponentQuery.query('example').body.mask(); use body instead of getEl()
I have the 2 views for my model. One creates the ul view, the other add the li elements. The views work but they do not update after the destroy function is called. I've tried various ways to bind to the render function, but it is not being called after this.model.destroy(); What am I missing?
var NoteListView = Backbone.View.extend({
tagName:'ul',
className: 'note-group',
initialize:function () {
_.bindAll(this, "render"); // I've tried all these:
this.model.bind("change", this.render, this);
this.model.bind("destroy", this.render, this);
this.model.bind("reset", this.render, this);
this.model.bind('change', _.bind(this.render, this));
this.model.on('change',this.render,this);
},
render:function (eventName) {
_.each(this.model.models, function (note) {
$(this.el).append(new NoteListItemView({
model:note
}).render().el);
}, this);
return this;
}
});
var NoteListItemView = Backbone.View.extend({
tagName:"li",
className: 'note-item',
template:_.template($('#tpl-note-item').html()),
initizlize:function(){
this.model.on('change',this.render,this);
},
render:function (eventName) {
$(this.el).html(this.template(this.model.toJSON()));
return this;
},
events: {
"click .note-btn-delete": "deleteNote"
},
deleteNote: function(e){
this.model.destroy();
}
});
Edit: here's the Collection:
var NoteCollection = Backbone.Collection.extend({
model:Note,
url:"api.php/notes",
initialize: function (models){
this.filtered = new Backbone.Collection(models);
},
filterByCid: function(id) {
var filtered = _.filter(this.models, function (model) {
if (id==0) return true;
return model.get("contactid") == id;
});
}
});
In the router:
this.noteList = new NoteCollection();
this.noteList.fetch({data:{contactid:id},
success: function (collection){
if (collection.length>0){
$('#note-container').html(new NoteListView({model:collection}).render().el);
}
else {
$('#note-container').html('No notes');
}
}
})
I see 2 issues with enter code here your code.
First
You are not listening to the remove event on the NodeListItemView
Second
_.each(this.model.models,
supposed to be
_.each(this.collection.models,
If models is present on the model, then it is supposed to be in the options of the model
_.each(this.model.options.models,
Code
var NoteListView = Backbone.View.extend({
tagName: 'ul',
className: 'note-group',
initialize: function () {
this.listenTo.on(this.collection, 'reset', this.render);
},
render: function (eventName) {
_.each(this.collection.models, function (note) {
$(this.el).append(new NoteListItemView({
model: note
}).render().el);
}, this);
return this;
}
});
var NoteListItemView = Backbone.View.extend({
tagName: "li",
className: 'note-item',
template: _.template($('#tpl-note-item').html()),
initizlize: function () {
_.bindAll(this, "deleteNote", "removeView");
this.listenTo.on(this.model, 'change', this.render);
this.listenTo.on(this.model, 'remove', this.removeView);
},
render: function (eventName) {
$(this.el).html(this.template(this.model.toJSON()));
return this;
},
events: {
"click .note-btn-delete": "deleteNote"
},
deleteNote: function (e) {
this.model.destroy();
},
removeView : function() {
this.remove();
}
});
EDIT
Change this line
new NoteListView({model:collection}).render().el
to use collection instead
new NoteListView({collection :collection}).render().el
And I do not believe your fetch method takes in any data
this.noteList.fetch({data:{contactid:id})
this.noteList.fetch()
It only takes in success and error callbacks
If I create a modal window:
Ext.define('myWindow', {
extend: 'Ext.Container',
alias: 'widget.myWindow',
floating: true,
modal: true,
listeners:
'onMaskClick???': { close the window }
.....
}
How do I know when a user has clicked on the mask outside the window? In Sench Touch, there is a config hideOnMaskTap that lets me specify. What is the event/config for extJS?
Tramway's case (sort of) works on modal or non modal windows. But not in case child components like the boundlist of a combobox float outside the windows boundaries.
However if you use modal windows anyway you can listen for a click event on the mask like this.
Ext.define('myWindow', {
extend: 'Ext.window.Window',
alias: 'widget.myWindow',
floating: true,
modal: true,
initComponent: function () {
var me = this;
me.callParent(arguments);
me.mon(Ext.getBody(), 'click', function(el, e){
me.close(me.closeAction);
}, me, { delegate: '.x-mask' });
}
});
You can listen all click events, then check if click position is out of the window
Ext.define('myWindow', {
extend: 'Ext.Container',
alias: 'widget.myWindow',
floating: true,
modal: true,
initComponent: function () {
this.initEvents();
this.callParent();
},
initEvents: function () {
//make sure your window is rendered and have sizes and position
if(!this.rendered) {
this.on('afterrender', this.initEvents, this, {single: true});
return;
}
this.mon(Ext.getBody(), 'click', this._checkCloseClick, this);
}
_checkCloseClick: function (event) {
var cx = event.getX(), cy = event.getY(),
box = this.getBox();
if (cx < box.x || cx > box.x + box.width || cy < box.y || cy > box.y + box.height) {
//clean up listener listener
this.mun(Ext.getBody(), 'click', this._checkCloseClick, this);
this.close();
}
}
}
You can try this also:
Ext.getBody().on('click', function(e, t){
var el = win.getEl();
if (!(el.dom === t || el.contains(t))) {
win.close();
}
});
I found adding a listener to the body and checking css classes felt a little hackey to me. You can actually override the private method _onMaskClick of Ext.ZIndexManager (see, completely not hackey). Which allows you to add your own configuration parameter (and even event) to all windows.
Ext.define('MyApp.ux.ZIndexManager_maskClick', {
override: 'Ext.ZIndexManager',
_onMaskClick: function ()
{
if (this.front)
{
var allowed = this.front.fireEvent('maskclick', this.front, this.mask);
if (allowed !== false && this.front.closeOnMaskClick)
this.front.close();
}
return this.callParent(arguments);
},
});