ColdFusion and leveraging ExtJS from within - Part III
Tags: Coldfusion, extJS
Part III of using ExtJS to create a custom widget using what comes with ColdFusion.
In the last post I quickly touched on creating a template that will be our UI container, I would like to very quickly go back to that very quickly to explain it a bit more.
If you remember we have used the following as our template.
tpls.master = new Ext.Template(
'<div style="width:100%; position:static;" class="x-layout-panel">',
' <div id="search-tb"></div>',
' <div id="search-results" class="search-results"></div>',
' <div id="page-tb"></div>',
'</div>'
);
tpls.master.disableformats = true;
}
Now you will notice that there are 3 divs wrapped with an outer div, the 3 inner divs are what is really going to define the way the widget is going to look. The 2 that end in tb are what we have set aside for adding a toolbar, the top toolbar is going to be were our search or filtering is going to be added, where as the page is going to be later for adding a pagination toolbar.
Search Toolbar
Before we begin adding the code for the toolbar we are going to need to use a datastore , that will hold the information that is going to be returned from the server. So in the initComponent section we need to add the following code.
proxy: new Ext.data.HttpProxy({url: this.bindUrl}),
reader: new Ext.data.JsonReader({root: 'records', totalProperty: 'recordcount', id: 'id'},
[{name: 'questionid'}, {name: 'question'}, {name: 'answer'}]),
baseParams: {limit:5 }
});
What we have now added to the code is the ability to retrieve data from the server, as a Json structure. You'll notice that we then use this to define the way the Json structure is going to look, the root of the structure is going to be records, with an array of questionid, question and answer. Which will end up looking something like this.
"recordcount":1,
"records":[
{
"questionid":1,
"answer":"the answer",
"question":"this is the question"
}
]
}
Last but not least you'll also notice that we are setting another config option as baseParams in the JsonReader as well, this is the number of records that we wish to return to the widget. This will be used in the pagination, so for now you can ignore that until we setup the pagination toolbar.
One more component needed
So that we can begin to create the search filtering option to our widget, we need to create one more extra component. This can be just added to the bottom of the current JS file that we have our current widget in, the code is basically extending another component that is going to hold the trigger field and the search input box. I won't go into full detail on what this is about, as it is fairly simple.
initComponent : function(){
Ext.app.SearchField.superclass.initComponent.call(this);
this.on('specialkey', function(f, e){
if(e.getKey() == e.ENTER){
this.onTrigger2Click();
}
}, this);
},
validationEvent:false,
validateOnBlur:false,
trigger1Class:'x-form-clear-trigger',
trigger2Class:'x-form-search-trigger',
hideTrigger1:true,
width:180,
hasSearch : false,
paramName : 'query',
onTrigger1Click : function(){
if(this.hasSearch){
var o = {start: 0};
o[this.paramName] = '';
this.store.reload({params:o});
this.el.dom.value = '';
this.triggers[0].hide();
this.hasSearch = false;
}
},
onTrigger2Click : function(){
var v = this.getRawValue();
if(v.length < 1){
this.onTrigger1Click();
return;
}
var o = {start: 0};
o[this.paramName] = v;
this.store.reload({params:o});
this.hasSearch = true;
this.triggers[0].show();
}
});
As you can see this has a few config properties and 2 methods, the methods are the actual trigger fields for the options that apply to the search field. One will clear the field so that it is empty again, the other will load the data from the server.
Setting up the Toolbar
We also need to create another template that is going to be the basis of how to style the data that will be returned from the server, this is fairly simple template again and we will need to add this to the onRender section after we update the container. So it should look like this.
var html = this.templates.master.apply();
container.update(html);
var resultTpl = new Ext.Template(
'<tpl for=".">',
'<div class="search-item">',
'<div class="searchQuestion">{question}</div>',
'<div class="searchAnswer">{answer}</div>',
'</div>',
'</tpl>'
);
this.view = new Ext.View('search-results', resultTpl, {store: this.ds});
Again we have classes to define how we might want the data to render or be styled, the line with the this.view is saying that we will apply the results from the server to the container element of search-results. Which was defined in our first template, and we are going to use the second template to define what it will look like, and we will use the datastore that we defined earlier.
The reason we define the datastore for the creation of the view, is that you will notice that in the template is 2 extra fields that match the records that get returned from the server. That means that when the data is rendered, the data will be pulled from the record store and replaced in the right position.
Now lets add the toolbar code for the search.
store: this.ds,
width:420
});
var tb = new Ext.Toolbar('search-tb', ['FAQ Search: ', ' ', this.searchField]);
Now this is fairly straight forward, and it is basically saying that we are going to create an instance of the new extended component. We are defining the width of this component and attaching it to the datastore, this is because the component we added earlier needs to know how to get the data when the trigger field is pushed or clicked. The next part of the code is basically then creating an instance of the toolbar component, we are going to attach it to the search-tb container in our first template. We are going to then give it a label of FAQ Search and then attach the component searchField that we instantiated and add it to the toolbar.
And we now have a search field in our component.
What's Left
To make this really work we are now going to add a key handler to the searchField, and we are then going to load data from the server.
this.ds.load({params:{start:0, limit:5}});
What we have basically said in this code is we are going to apply the current scope of this component, and give it to the event keyup. Which is another method we'll add to our component, and we set a buffer of 300 which is basically how long after we stop typing that the data will be loaded from the server.
var length = this.searchField.getValue().toString().length;
if(0 === length || this.minChars <= length) {
this.searchField.onTrigger2Click();
}
}
This code for the key handler is very straight forward we are saying that we need to have a minimum of 4 keys pressed before we can return any data, and if the field is empty we are not going to trigger the loading of the data.
To Finish Up
So that's pretty much the beginning of our widget, and to finish up for today we also need to add the following properties to our component as well.
And should look like this when we add it.
minChars: 4,
bindUrl: null,
And last but not least, we also need to modify our html section now. So that we then pass this info in.
Ext.onReady(function(){
var faq = new Ext.ux.faqContainer('faqContent', {bindUrl: '/component/mycfc?method=getRecords', minChars: 7} );
});
</script>
As you can see we can modify the properties by using the config option, of the component by passing the bindUrl and the minChars and override the properties of the components defaults.
Ok that's it for today and in my last instalment, I will show how to setup the pagination toolbar.
There are no comments for this entry.



TweetBacks