You can easily create a custom component from any existing one, by using the dhx.protoUI() command.
In short, the technique for creating is the following:
dhx.protoUI({ name:"mylist", // the name of a new component $init:function(config){ //config - configuration options //a custom constructor code } ... any custom methods can be defined here ... }, dhx.ui.list); //the name of the base component which the new component inherits from
and later you can use it in a layout as any normal component:
dhx.ui({ rows:[ { view:"mylist", data:"some.json", ... }, ... ] })
Before we describe how the mentioned technique works, it helps to summarize the main methods and properties you may use while developing a component.
Properties:
this.$ready.push(...);
Methods:
As an example, let's create a simple component shown in the image below (the first row of the first column). Maybe, it doesn't have any practical use but it's a good way to explain creating a custom component.
Our future component can be characterized by the following:
You can apply the following steps while developing the component:
For our component we chose the following, the most appropriate classes:
So, the second parameter of the dhx.protoUI() command will be dhx.MouseEvents, dhx.EventSystem, dhx.ui.baseview.
dhx.protoUI({ /*.. component definition...*/}, dhx.MouseEvents, dhx.EventSystem, dhx.ui.baseview);
From this action we will start defining the component. We'll take the name 'custom'.
dhx.protoUI({ name:"custom", ... }, dhx.MouseEvents, dhx.EventSystem, dhx.ui.baseview);
$init function answers for initialization.
In our case it will have the following code:
$init:function(config){ this.$view.className = "my_control";// sets css class for the component this.$view.innerHTML = "<div class='item1'></div><div class='item2'></div><div class='item3'></div>";// specifies the appearance of the component }
At this step we must decide which properties our component should have.
We will define 3 properties:
item1_setter:function(value){ if(value) this.$view.childNodes[0].innerHTML = value; return value; }, item2_setter:function(value){ if(value) this.$view.childNodes[1].innerHTML = value; return value; }, item3_setter:function(value){ if(value) this.$view.childNodes[2].innerHTML = value; return value; }
We have 2 variants to set the initial height of the component:
Let's consider 2 variants.
1. height (as well as width) is a keyword and if you set this property in the defaults, the parser will recognize and process it.
defaults:{ height:100 }
2. But if you use in the defaults the other name it won't be recognized and processed. In such a case you will need to use the method $getSize as well.
So, in the defaults we will specify some property (you can refer to this property later through this.config.[someProperty]) and through $getSize set the initial height to its value.
defaults:{ controlHeight:100 }, $getSize:function(){ return [1,-1,0,this.config.controlHeight]; }
The parent container can change its size and it will influence on proportions of the columns of our component. To provide the same width of the columns in any situation we will redefine the method $setSize.
$setSize:function(x,y){ if (dhx.ui.view.prototype.$setSize.call(this,x,y)){ var itemWidth = Math.round(this.$width/3); for(var i=0;i<3;i++){ this.$view.childNodes[i].style.width = (i==2?this.$width-(itemWidth*2):itemWidth) +"px"; this.$view.childNodes[i].style.height = this.$height+"px"; } } }
dhx.ui.view.prototype.$setSize.call(this,x,y) - the $setSize method of the parent container. We called it to set size of the whole component.
The method $setSize is called each time when the script sets or changes the size and returns true (size was set) of false (size was changed). As we want to redefine the method just in case of changing size - we'll put it into if block.