why is needed add appearances aliases to widgets build by _createChildControlImpl()? - qooxdoo

I'm creating some UI compose by a TabView inside another TabView.
To the insider TabView I add a specific tab, all via _createChildControlImpl() implementation,
some like
qx.Class.define('rigel.view.Dashboard', {
extend: qx.ui.container.Composite,
construct: function(layout) {
this.base(arguments, layout);
this.add(this.getChildControl("container"), {edge: 'center'});
},
// overridden
_createChildControlImpl: function(id, hash) {
var control;
switch (id) {
case "container":
control = new my.view.tabview.ResourcesCat();
break;
...
and
qx.Class.define('my.view.tabview.ResourcesCat', {
extend: qx.ui.tabview.TabView,
_createChildControlImpl: function(id, hash) {
var control;
switch(id) {
case "static":
control = new qx.ui.tabview.Page('', 'icon.png');
this.add(control);
I do this for set that TabPage only in some cases.
Anyway, I do not understand why for each widget buil by _createChildControlImpl I have to add aliases to Appearance if I do not want change any of theme.
So I have
"widget/tabview": "tabview",
"tabview/static": "tabview-page",
"tabview/static/tab-name": "tabview-page",
I will prefer some way to avoid add appareance aliases for each widget, and keep the construction inside of _createChildControlImpl.
Thanks.

_createChildControlImpl is designed for UI components which form part of the main widget - for example, TabView has child controls which are the button bar and the composite for holding the pages; a Page has a button for the tab; a button has a child control for an icon and another for the label; and so on
For all of those "child controls", their styling is often very much part of the styling of the parent widget which is why Appearances support paths like "button/icon" or "button/label".
This can be slightly confusing because a "child control" is just another widget, but its important to keep the distinction especially when it comes to theming.
In your example, the "static" and "container" widgets should not be instantiated as child controls at all - for example, you could initialise them as member variables inside a constructor:
qx.Class.define('rigel.view.Dashboard', {
extend: qx.ui.container.Composite,
construct: function(layout) {
this.base(arguments, layout);
this.__container = new my.view.tabview.ResourcesCat();
this.add(this.__container, {edge: 'center'});
},
and
qx.Class.define('my.view.tabview.ResourcesCat', {
extend: qx.ui.tabview.TabView,
construct: function() {
this.base(arguments);
this.__static = new qx.ui.tabview.Page('', 'icon.png');
this.add(this.__static);
}

Related

How can I add two icons to button

I want to create a button with two icons. One at the left edge and at the right edge.
How can I do it?
example:
https://archive.qooxdoo.org/current/playground/#Hello%20World-ria
The idea is to redefine _createChildControlImpl method and create the second icon there:
qx.Class.define("myapp.Button", {
extend : qx.ui.form.Button,
construct(name, path){
this.base(arguments, name, path);
this._createChildControl("secondicon");
},
members: {
_createChildControlImpl(id, hash){
let control;
switch(id) {
case "secondicon":
control = new qx.ui.basic.Image(this.getIcon());
this._add(control);
break;
}
return control || super._createChildControlImpl(id);
}
}
});
Alternatively, you can take advantage of the fact that every widget is in essence a container. You can call the button's _add method, as shown here:
var button1 =
new qx.ui.form.Button("First Button", "icon/22/apps/internet-web-browser.png");
// Add another icon. It'll be added after whatever has already been
// added to the button, which is the original icon and the button text.
button1._add(new qx.ui.basic.Image("icon/22/apps/internet-web-browser.png"));

how to add an event that fires after scrolling the scrollbar to the end

I am working with standalone (not mobile) and I think it is _getScroll method for reaching it.
how to implement it here qooxdoo selectbox example
I found similar for mobile implementing virtual scrolling list console.log says container._getScroll is not a function.
The idea is to get scrollbar from a widget, the scrollbar you are needed is NativeScrollbar of the widget qx.ui.list.List. Then add event handler for a "scroll" event. In handler u have to compare current position of scroll and maximum.
Try the code below (eg copy and paste into the Qooxdoo playground).
qx.Class.define("SelectBoxWithScrollEndEvent", {
extend: qx.ui.form.SelectBox,
construct: function(){
this.base(arguments);
this.__setupScroll();
},
events: {
"scrollEndHappened": "qx.event.type.Event"
},
members: {
__setupScroll: function(){
const list = this.getChildControl("list");
const scrollbar = list.getChildControl("scrollbar-y");
scrollbar.addListener("scroll", function(e){
if (scrollbar.getMaximum() === scrollbar.getPosition()){
this.fireEvent("scrollEndHappened");
}}, this);
}
}
});
const box = new SelectBoxWithScrollEndEvent();
const data = new qx.data.Array([1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]);
const controller = new qx.data.controller.List(data, box);
box.addListener("scrollEndHappened", function(){
alert("SCROLL HAPPENED ALERT");
}, this);
this.getRoot().add(box);

How to access user defined methods of widget parent

I have a parent widget which extends Window class (qx.ui.window.Window) and this window now has couple of children (I have created the children by overriding childControlImpl).
Now I would like to access my methods in Parent class from one of the child classes. I don't want to create an object to call the methods, instead I would like to use getLayoutParent method to do this.
But when I can call getLayoutParent method from the child class, all I can access are the built-in methods, but I can't access any methods which I have created.
How can I get to do this ?
code Sample:
qx.Class.define("project.WrkAttrWindow",{
extend : qx.ui.window.Window,
construct: function() {
this.base(arguments);
this.__table = this._createChildControl("table");
},
members: {
__table:null
_createChildControlImpl : function(id)
{
var control;
switch(id)
{
case "table":
control = new project.WrkAttrTable();
this.add(control);
break;
}
return control || this.base(arguments, id);
},
getPrjId:function() {
console.log(I want to call this function);
}
});
Child Widget
qx.Class.define("project.WrkAttrTable",{
extend: qx.ui.table.Table,
statics: {
colKeys:["id","name","description"]
},
construct: function() {
this.base(arguments);
//some code here
},
members:
{
//call parent method from here
this.getLayoutParent().getPrjId(); // does not work
}
});
Despite the cross-post on Nabble, here is the gist from the answer:
In _createChildControlImpl, use this._add instead of this.add.

Backbone: getting view object from the element

Let's say I have some items to show in a list. The list has a view that aggregates all the items as item views. Now I want to handle the click events on the item views and I delegate the handling to the list view.
Let's see some example code:
ItemView = Backbone.View.extend({
className: 'item',
initialize: function() {
this.$el.data('backbone-view', this);
}
});
Note that I am attaching the view object itself as a property of the root element, which essentially creates a circular reference situation for the view and the element.
ListView = Backbone.View.extend({
initialize: function() {
// contains the item views
this.items = [];
// click event delegation
this.$el.click(_.bind(this._onClick, this));
},
addItem: function(v) {
if ( !(v instanceof ItemView) ) return;
this.items.push(v);
this.$el.append(v.el);
},
_onClick: function(e) {
var el = $(e.target).closest('.item'),
view = el.data('backbone-view');
// do something with the view
}
});
This is a very general pattern whenever one has to deal with any kind of list views.
I am getting the item view back in the handler via the data property that I set on the item on the initialization time. I need to get item view because anything that I want to do on the item as part of handling the click event is based on the view.
Also note that I am using closest because item view may be complex and the actual target of the click event may be a descendant of the root element.
So the question: is this way to binding the view to it's root element via data properties the right approach -- in particular when considering garbage collection and memory leaks? Can there be something better than this?
You should catch the events in the child view. In my opinion, any Backbone view should only handle the DOM events of its element and its children. If views are nested, as yours are, the most specific view should handle the events.
If you want to delegate handling to the parent view, you can trigger a backbone event in the ItemView, and listen to those in the ListView.
ItemView = Backbone.View.extend({
events: {
"click":"onClick"
},
onClick: function() {
//trigger a custom event, passing the view as first argument
this.trigger('click', this);
}
});
ListView = Backbone.View.extend({
addItem: function(v) {
if ( !(v instanceof ItemView) ) return;
//listen to custom event
this.listenTo(v, 'click', this._onClick);
this.items.push(v);
this.$el.append(v.el);
},
_onClick:function(itemView) {
//...
}
});
If the click event represents some "higher level" action, such as select or activate, you should name your custom events as such. This way you can create a logical, robust interface between your views without concerning the parent ListView with the implementation details of its child. Only ItemView should know that whether it's been clicked, hovered, double clicked etc.

Backbone Boilerplate Layout Manager

Can someone help explain / provide an example on how to use the LayoutManager within the Backbone Bolierplate?
Within app.js I can see a useLayout function that extends the main app object. Within here it appears to be setting a base layout element:
// Helper for using layouts.
useLayout: function(name, options) {
// Enable variable arity by allowing the first argument to be the options
// object and omitting the name argument.
if (_.isObject(name)) {
options = name;
}
// Ensure options is an object.
options = options || {};
// If a name property was specified use that as the template.
if (_.isString(name)) {
options.template = name;
}
// Create a new Layout with options.
var layout = new Backbone.Layout(_.extend({
el: "#main"
}, options));
// Cache the refererence.
return this.layout = layout;
}
Is that correct? If so, do I somehow the use the 'UseLayout' function with the applications Router? ...to add different UI elements/nested views to the main view?
Thanks.
I will usually have an "app" object that stores all my settings needed throughout the application. This object then extends some useful functions like the one you listed above. For example:
var app = {
// The root path to run the application.
root: "/",
anotherGlobalValue: "something",
apiUrl: "http://some.url"
};
// Mix Backbone.Events, modules, and layout management into the app object.
return _.extend(app, {
// Create a custom object with a nested Views object.
module: function(additionalProps) {
return _.extend({ Views: {} }, additionalProps);
},
// Helper for using layouts.
useLayout: function(options) {
// Create a new Layout with options.
var layout = new Backbone.Layout(_.extend({
el: "#main"
}, options));
return this.layout = layout;
},
// Helper for using form layouts.
anotherUsefulFunction: function(options) {
// Something useful
}
}, Backbone.Events);
});
Now in my router I would do something like:
app.useLayout({ template: "layout/home" })
.setViews({
".promotional-items": new Promotions.Views.PromotionNavigation(),
".featured-container": new Media.Views.FeaturedSlider({
vehicles: app.vehicles,
collection: featuredCollection
})
}).render().then(function() {
//Do something once the layout has rendered.
});
I have just taken a sample from one of my applications, but I am sure you can get the idea. My main layout is basically just a layout template file which holds the elements so the views can be injected into their respective holders.
You would use it as if you're using a regular Backbone View. Instead of building the View directly, you can use this to create a new instance. The code you posted is a wrapper object on top of the Backbone Layout Manager extension with el: #main set as the default View element which is overridable.
var layout = new useLayout({ template: "#viewElement", ... });

Resources