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.
Related
What is the difference between class method, class property which is a function, and class property which is an arrow function? Does the this keyword behave differently in the different variants of the method?
class Greeter {
constructor() {
this.greet();
this.greet2();
this.greet3();
}
greet() {
console.log('greet1', this);
}
greet2 = () => {
console.log('greet2', this);
}
greet3 = function() {
console.log('greet3', this);
}
}
let bla = new Greeter();
This is the resulting JavaScript when transpiled from TypeScript.
var Greeter = /** #class */ (function () {
function Greeter() {
var _this = this;
this.greet2 = function () {
console.log('greet2', _this);
};
this.greet3 = function () {
console.log('greet3', this);
};
this.greet();
this.greet2();
this.greet3();
}
Greeter.prototype.greet = function () {
console.log('greet1', this);
};
return Greeter;
}());
var bla = new Greeter();
My TypeScript version is 3.4.5.
There are differences between all 3 versions. This differences are in 3 areas:
Who is this at runtime
Where the function is assigned
What is the type of this in typescript.
Lets start with where they work just the same. Consider this class, with a class field:
class Greeter {
constructor(private x: string) {
}
greet() {
console.log('greet1', this.x);
}
greet2 = () => {
console.log('greet2', this.x);
}
greet3 = function () {
// this is typed as any
console.log('greet3', this.x);
}
}
let bla = new Greeter(" me");
With this class all 3 function calls will print as expected: 'greet* me' when invoked on bla
bla.greet()
bla.greet2()
bla.greet3()
Who is this at runtime
Arrow functions capture this from the declaration context, so this in greet2 is always guaranteed to be the class instance that created this function. The other versions (the method and function) make no such guarantees.
So in this code not all 3 print the same text:
function call(fn: () => void) {
fn();
}
call(bla.greet) // greet1 undefined
call(bla.greet2) //greet2 me
call(bla.greet3) // greet3 undefined
This is particularly important when passing the function as an event handler to another component.
Where the function is assigned
Class methods (such as greet) are assigned on the prototype, field initializations (such as greet2 and greet3) are assigned in the constructor. This means that greet2 and greet3 will have a larger memory footprint as they require an allocation of a fresh closure each time Greeter is instantiated.
What is the type of this in typescript.
Typescript will type this as an instance of Greeter in both the method (greet) and the arrow function (greet2) but will type this as any in greet3. This will make it an error if you try to use this in greet3 under noImplictAny
When to use them
Use the method syntax if this function will not be passed as an event handler to another component (unless you use bind or something else to ensure this remains the instance of the class)
Use arrow function syntax when your function will be passed around to other components and you need access to this inside the function.
Can't really think of a good use case for this, generally avoid.
this keyword difference:
In the above all three have same this but you will see the difference when you will pass the method to another functions.
class Greeter {
constructor() {
}
greet() {
console.log(this);
}
greet2 = () => {
console.log(this);
}
greet3 = function() {
console.log(this);
}
}
let bla = new Greeter();
function wrapper(f){
f();
}
wrapper(bla.greet) //undefined
wrapper(bla.greet2) //Greeter
wrapper(bla.greet3) //undefined
But there is another difference that the first method is on the prototype of class while other two are not. They are the method of instance of object.
class Greeter {
constructor() {
}
greet() {
console.log('greet1', this);
}
greet2 = () => {
console.log('greet2', this);
}
greet3 = function() {
console.log('greet3', this);
}
}
let bla = new Greeter();
console.log(Object.getOwnPropertyNames(Greeter.prototype))
If I have in the class -> str = "my string"; and in all the 3 methods I can say console.log(this.str) and it outputs the "my string". But I wonder - is this really actually the same thing
No they are not same things. As I mentioned that greet2 and greet3 will not be on Greeter.prototype instead they will be on the instance itself. It mean that if you create 1000 instances of Greeter their will be 1000 different method(greet2 and greet3) stored in memory for 1000 different instances. But there will a single greet method for all the instances.
See the below snippet with two instances of Greeter()
I'd like to mark each field wrapping container with custom css class when field is focused and remove that class when field is blured. So I would like to attach focus/blur event methods to every form field component I add to any form.
in Ext 4 I did it like this:
Ext.ComponentManager.all.on('add', function(map, key, item) {
// Check if item is a Window and do whatever
if (item instanceof Ext.form.field.Base) {
item.on('focus', function(theField) {
var parentDom = null; //theField.bodyEl.findParent('.x-form-fieldcontainer');
if (!parentDom) {
parentDom = theField.bodyEl.findParent('.x-field');
}
if (parentDom) {
var parentEl = Ext.get(parentDom);
parentEl.addCls('focused-field');
}
}, item);
item.on('blur', function(theField) {
var parentDom = null; //theField.bodyEl.findParent('.x-form-fieldcontainer');
if (!parentDom) {
parentDom = theField.bodyEl.findParent('.x-field');
}
if (parentDom) {
var parentEl = Ext.get(parentDom);
parentEl.removeCls('focused-field');
}
}, item);
}
});
I'm not sure how to do it in ExtJS 6
Any help appreciated
Regards
Armando
You don`t need it, ExtJs has already '.x-field-focus' css class which is added to wrapper element on focus, so you can try to add your styles to the existing class. You can also look at the $form-field-focus-* theme variables..
Anyway, if you want to add this functionality, you can override the 'Ext.form.field.Base' class which is the parent of all the form fields.
Something like this:
Ext.define('overrides.form.field.Base', {
override: 'Ext.form.field.Base',
customCssOnFocus: 'focused-field',
initEvents: function() {
this.callParent(arguments);
this.on('focus', this.addCustomCssOnFocus, this);
this.on('blur', this.removeCustomCssOnBlur, this);
},
addCustomCssOnFocus: function() {
Ext.get(this.getEl().findParent('.x-field')).addCls(this.customCssOnFocus);
},
removeCustomCssOnBlur: function() {
Ext.get(this.getEl().findParent('.x-field')).removeCls(this.customCssOnFocus);
}
});
I'm using a TypeScript class to define a controller in AngularJS:
class TrialsCtrl {
constructor(private $scope: ITrialsScope, private ResourceServices: ResourceServices) {
this.loadTrials();
}
loadTrials() {
console.log("TrialsCtrl:", this);
this.Trial.query().then((result) => {
this.$scope.Trials = result;
});
}
remove(Trial: IRestTrial) {
this.ResourceServices.remove(Trial, this.loadTrials);
}
}
angular.module("app").controller("TrialsCtrl", TrialsCtrl);
I'm refactoring common controller methods into a service.
class ResourceServices {
public remove(resource, reload) {
if (confirm("Are you sure you want to delete this?")) {
resource.remove().then(() => {
reload();
});
}
}
}
angular.module("app").service("ResourceServices", ResourceServices);
The console log shows that this is referencing the window context when I want it to be TrialsCtrl. My problem is that the reload() method needs to run in the context of TrialsCtrl, so that it can access this.Trial and this.$scope. How can I tell the reload() method to set this as the TrialsCtrl? Or is there some other workaround I should be using for this kind of thing?
Have you tried:
this.ResourceServices.remove(Trial, this.loadTrials.bind(this));
or
this.ResourceServices.remove(Trial, () => this.loadTrials());
For methods that are supposed to be passed as callbacks (as with this.loadTrials) it is preferable to define them as arrows,
loadTrials = () => { ... }
So they keep the context whether Function.prototype.bind is used or not.
Alternatively, a decorator may be used on the method (like core-decorators #autobind) to bind a method while still defining it on class prototype:
#autobind
loadTrials() { ... }
I try to use jstree control in my TypeScript code for an angularjs application. I use jstree typings and jstree.directive to show a tree. Everything works to the point when I need to handle menu item click and call for the base method. Inside of my action there is no "this" (contextmenu) scope. Any suggestions?
class MapTreeViewController {
mapTreeView: JSTree;
vm.mapTreeView = $('#jstree').jstree(
{
'core': { 'data': items },
'plugins': ['themes', 'ui', 'contextmenu'],
'contextmenu': {
'items': function(node:any) {
var vmNode = this;
return {
'rename': { // rename menu item
'label': 'Rename',
'action': function(obj) {
this.rename(obj);
}
}
};
}
}
});
}
Somewhere inside of a method.
this is not an instance - take a look at the original function to see how to obtain an instance:
https://github.com/vakata/jstree/blob/master/src/jstree.contextmenu.js#L84
"action" : function (data) {
var inst = $.jstree.reference(data.reference),
...
What is the correct way to pass a view variable from the URL to a View Model to filter the result?
For example:
dataSource: new kendo.DataSource( {
transport: {
read: {
url: 'http://api.endpoint.com/resource',
}
parameterMap: function(options,type) {
if (type === 'read') {
return {
FormID: view.params.FormID
};
}
}
});
In the example above, there's a parameter in the URL called "FormID" and I would like to pass that value right to the parameterMap function. There is no "view" object, so I'm just putting that as an example.
I tried hooking into to the "data-show" and "data-init" functions to set this value to use, but the datasource fetches the data before these functions run.
Thanks
The configuration option options.transport.read can be a function, so you can compose the url there:
dataSource: new kendo.DataSource({
transport: {
read: function (options) {
// get the id from wherever it is stored (e.g. your list view)
var resourceId = getResourceId();
$.ajax({
url: 'http://api.endpoint.com/resource/' + resourceId,
dataType: "jsonp",
success: function (result) {
options.success(result);
},
error: function (result) {
options.error(result);
}
});
}
}
});
To connect this with your list view, you could use the listview's change event:
data-bind="source: pnrfeedsDataSource, events: { change: onListViewChange }"
then in viewModel.onListViewChange you could set the appropriate resource id for the item that was clicked on:
// the view model you bind the list view to
var viewModel = kendo.observable({
// ..., your other properties
onListViewChange: function (e) {
var element = e.sender.select(); // clicked list element
var uid = $(element).data("uid");
var dataItem = this.dataSource.getByUid(uid);
// assuming your data item in the data source has the id
// in dataItem.ResourceId
this._selectedResource = dataItem.ResourceId;
}
});
Then getResourceId() could get it from viewModel._selectedResource (or it could be a getter on the viewModel itself). I'm not sure how all of this is structured in your code, so it's difficult to give more advice; maybe you could add a link to jsfiddle for illustration.
You may use a "global" variable or a field in the viewmodel for that purpose. Something like
var vm = kendo.observable({
FormID: null,
dataSource: new kendo.DataSource( {
transport: {
read: {
url: 'http://api.endpoint.com/resource',
}
parameterMap: function(options,type) {
if (type === 'read') {
return {
FormID: vm.FormID
};
}
}
})
});
function viewShow(e) {
vm.set("FormID", e.view.params.FormID);
// at this point it is usually a good idea to invoke the datasource read() method.
vm.dataSource.read();
}
The datasource will fetch the data before the view show event if a widget is bound to it. You can work around this problem by setting the widget autoBind configuration option to false - all data-bound Kendo UI widgets support it.