How to (properly) render additional data in grid with RowExpander - javascript

I'm trying to render some data in the rowbody in a grid (with the RowExpander plugin).
My problem is that the ol' rowBodyTpl isn't enough for me as this data is from Records on Stores from the record being rendered (hmmm...).
Putting it simply: Every record of the grid has a store in it (lets call it Items). So, I want to render the record data and some data of the Items records aswell.
What would be the best(ish) way of doing so?
Override the renderer function of the rowexpander plugin, override the getAdditionalData, or none of these?
Thank you.

I know this question is a few years old, but here's a trick I currently use to handle this kind of situation. It takes advantage of "verbatim" blocks that XTemplates allow. These allow you to execute arbitrary code inside an XTemplate by wrapping it with {% ... %}. Inside those code blocks, this is set to the XTemplate itself. The XTemplate has an owner property that, in our case, references the RowExpander plugin itself, which, in turn, has a grid property to reference the grid. So, something like this allows you to add arbitrary data to the values passed into rowBodyTpl.
Ext.create('Ext.grid.Panel', {
...
injectRowBodyData: function(values) {
values.MyInjectedContent = "Here's some extra data!";
},
plugins: [
{
ptype: 'rowexpander',
rowBodyTpl: [
'{% this.owner.grid.injectRowBodyData(value); %}',
'<div>',
'<h1>{Title}</h1>',
'<p>{Content}</p>,
'<p>{MyInjectedContent}</p>',
'</div>'
]
}
]
});
Hhopefully Sencha will fix the plugin to provide a way to handle this in the future. But for now this works well. I tested this with v4.2.1.883, but this should work with any previous version of Ext 4. The only thing I can think of that may prevent it from working in the future is the XTemplate's owner property no longer being pointed to the plugin, or the plugin not having a reference to the grid with it's grid property.

How I "solve" this problem, it might help somebody else:
I overrode the getRowBodyFeatureData of the rowexpander plugin, as this function not only receives the data to be applied on the template, but also the record itself, so I just data added the extra stores/arrays from the record.
Not sure if its the best way, but hey... at least it works.

You can also use if else statements in rowBodyTpl:
Check for ":"
"<tpl if='phone == \":\"'>",
"<tpl else>",
"</tpl>"
Check for empty string
"<tpl if='phone == \"\"'>",
"</tpl>"
this sample is taken from here: link

This is how I usually do:
Ext.create('Ext.grid.Panel',{
border: true,
store: 'ds',
columns: []
plugins: [{
ptype: 'rowexpander',
rowBodyTpl : ['<p><b>Title:</b>{name}<br/><b>Description:</b> {description}<br/><b>Experiment Design:</b> {experimentdesign}</p>']
}],
renderTo:
});

Related

Confused on getting DataTables Render Text Helper?

I am trying to render my DataTables table so that it allows HTML characters to be shown.
From my reading it seems that this can be done using the DataTables Text Helper (as seen here https://datatables.net/manual/data/renderers)
In the example they give they simply put:
data: 'product',
render: $.fn.dataTable.render.text()
However when I have tried this it appears to do nothing at all as all the columns in my DataTable still don't show any HTML special characters (and no errors). I understand that my code is more complex than this example, but is there something simple I am missing?
var dataTableZ = $('#results_table').DataTable({
data: data.value,
render: $.fn.dataTable.render.text(),
/*
Unrelated Code surrounding buttons and column ordering
*/
columns: searchColumnDetails
});
(Where data.value is some data coming back from an Ajax call)
I have tried looking for answers to my question and it seems I am running a version of DataTables that includes this function (1.10.20), but none of the examples I could find online shed any light into my confusion.
Thank you for any assistance!
I Managed to find an answer to my question on the DataTables Forums!
Datatables doesn't have an option called render. There is a columns.render. You need to use either columns or columnDefs to to apply the render. Something like this:
columnDefs: [ {
targets: 0,
render: $.fn.dataTable.render.text() } ]
By putting this code into my code, it worked as intended.
Forum Post: https://datatables.net/forums/discussion/59325/render-text-helper-not-showing-html/p1?new=1

how to handle javascript that only runs on certain pages when bundled together

When working on small client sites, I often end up working with a main.js file that includes a bunch of jQuery plugins and small toggle functionality. Some of these code snippets are only relevant on certain pages, but ends up bundled together in one main.min.js file.
My question is, how do people write the individual code snippets in order to only execute that code when the correct page is being rendered?
Here's an example: Let's say I have a page with a search input field. This input is hooked up with jQuery autocomplete in order to show search suggestions as the user types. the code in main.js could look something like this:
var data = [
{
value: 'some value',
data: 'some data'
},
{...}
]
$('#autocomplete').autocomplete({
lookup: data,
lookupLimit: 10,
minChars: 3,
});
This code is only useful on the template that has that input field, but as main.js contains a bunch of other smaller bits like this that are useful globally and on other pages, the whole file is loaded on every pageview. What strategy should I use to only execute that piece of code when the page needs it?
I though of a few ways my self:
Check if the DOM-element (in this case #autocomplete) exists.
Check if the URL is == '/page-with-autocomplete'.
Use a class on , and check for that class i n order to run the script.
Other ideas? Any standard way to do this sort of thing? Anything considered a "best practice"?
Stick your JS in an if block and check for the unique DOM element on the page you want the script to run.
Although you can't just do:
if ( $('#my-el') ) {}
You have to check if the element has a length, like:
if ( $('#my-el').length ) {}

Extjs 4.1 pagingtoolbar default page

I want to change default page of pagination toolbar to 1 of 1 instead 0 of 0 in case of no record.Plus I am not using store proxy to request any records, so is there any way to accomplish it without using store proxy. According to my requirement user can add rows manually to the grid with the pagination toolbar showing page 1 and when rows exceeds 10 it moves to 2nd page.
In Ext it is possible to overload a component like Ext.toolbar.Paging with your own custom version. Simply specify an alias in your definition and you can us it just like the "native control."
In order to be sure that the approach would work, I set up a test project with a simple datasource and implemented enough of a replacement definition that I could see the "Ext.toolbar.Paging".getPagingItems method being fired in my custom definition.
From that point you can replace the code inside the definition of the original method to allow for a custom minimum in addition to the opportunity to overload the "updateInfo" method to make sure that during data reloads you're not plowing through your customizations.
In addition to these two things, you should (with a relatively small amount of effort) be able to implement on top of the control to support dynamically changing it's values based on the contents of your grid.
If you look at the documentation for ux.data.PagingStore you should be able to suss out the differences in using a remotely supplied store from something that is served with data locally.
Hope this helps you.
Code Sample:
Ext.define(
"Test.view.testview.TvPageBar",
{
extend: "Ext.toolbar.Paging",
alias: "widget.tvpagebar",
title: "Bob",
strictInit: function () {
"use strict";
console.log("TvPageBar init");
},
getPagingItems: function () {
console.log("getPagingItems", this);
this.callParent(arguments);
},
initComponent: function () {
this.strictInit();
this.callParent(arguments);
}
}
);

afterLabelTextTpl usage in extjs4

I need to display an image after a field label.
I am trying to see if I can use afterLabelTextTpl. But didnt find an example online
as how to use it.
Here is an idea of what I am trying to do. Can someone correct me syntatically..
{
xtype: 'combobox',
fieldLabel: 'Role',
editable:false,
store: roles_store,
triggerAction:'all',
name: 'role_id',
valueField: 'role_id',
displayField:'role_name',
afterLabelTextTpl : function() {
{
xtype: 'image',
src:'../www/css/slate/btn/question.png',
padding: '5 0 0 0',
cls:'pointer',
listeners: {
el:{
click: function() {
Ext.create('Ext.tip.Tip', {
closable:true,
padding: '0 0 0 0',
maxWidth:300,
html: "<b>read-only</b>: Has read access to all pages, but can make no changes.<br><br><b>user</b>: Can edit rules and commit to production.<br><br><b>admin</b>: Can edit rules, commit to production, and add/delete users.<br><br> "+supertext
}).showAt([810, 340]);
}
}
}
}
}
The afterLabelTextTpl is a template config, meaning that it takes either a string, an array of strings, or an instance of Ext.XTemplate and uses that to generate HTML.
There's no built-in way of creating a component via XTemplate (although a forum member created an extension called CTemplate that allows this). So if you want to go pure Ext JS, you're going to do a little more work.
NOTE: I don't have access to Ext JS 4.1.3 so what follows is an approximation, based on my experience with 4.1.0. You may need to tweak the code to get it just right, but it should provide a sufficient starting point.
Step 1: Setting up your afterLabelTextTpl. Try something like this:
afterLabelTextTpl:'<img id="combo_icon" style="padding-top:5px" class="pointer" src="../www/css/slate/btn/question.png"/>'
That should get your icon showing.
Step 2: Adding the click listener. There are two ways to go about this. Both methods assume you have a function called My.Name.Space.onImageClick. Obviously you can replace this name with whatever you want. Here's the function:
My.Name.Space.onImageClick = function(){
Ext.create('Ext.tip.Tip', {
closable: true,
padding: 0,
maxWidth: 300,
html: '<b>whatever you want here</b>'
}).showAt([810, 340]);
};
One method is to add the listener directly to the DOM.
'<img onclick="My.Name.Space.onImageClick();" /* the rest of the HTML here */ />'
The other method is to add the listener via Ext.dom.Element which is probably the better choice. You would need something like this in your combobox config:
listeners: {
afterrender: function(me){
var imgEl = Ext.get("combo_icon");
if(imgEl){
imgEl.on("click", My.Name.Space.onImageClick);
}
}
}
If you're having specific trouble getting this working, leave a comment and I'll help clarify what I can.
Its an XTemplate instance or a string.
From the docs:
An optional string or XTemplate configuration to insert
in the field markup after the label text. If an XTemplate is used, the
component's render data serves as the context.
So a string "Hello" will do, or anything that XTemplate will take

Dojo widget defaults

i'm currently writing a large scale application heavily based on the dojo toolkit. The whole app is working and standing, but one issue i can not find my way out with, is the creation of custom widgets. It would be useful because it would clean up my source code and also i can reuse this 'widgets' in later projects.
For example: i have a main toolbar, which i would like to call using
myapp.toolbar = new myapp.mainToolbar();
instead of using
myapp.toolbar = new new dijit.Toolbar({}, containerID);
var button1 = new dijit.form.Button({
label: 'Delete',
id: 'toolbarbutton1',
showLabel: true,
iconClass: "dijitEditorIcon dijitEditorIcon Delete"
});
myapp.toolbar.addChild(button1);
...
So in short: how do i set up the whole toolbar somewhere else and call it as a simple object? Trying to figure out dojo.declare('myapp.mainToolbar', dijit.Toolbar, {...}) but then i get a bunch of errors like 'startup function not existing' etc...
I'd like to do all this programmatically, so without the template html and css files in a custom widget.
A link to a good tutorial or howto would be nice, although google nor yahoo! will reveal any extra's on this matter for me... :)
There are multiple ways to do this.
It seems like your method of extending Toolbar should work (not sure why it didn't).
You can also declare a class that embeds Toolbar and the buttons, using widgetsInTemplate:
dojo.declare("MyToolbar", [dijit._Widget, dijit._Templated], {
_widgetsInTemplate: true,
templateString: '<div> <div dojoType=dijit.Toolbar>' +
' <button dojoType=dijit.form.Button ...
Note that the top node in MyToolbar can't have a dojoType, so I put Toolbar one level down.
Alternately you can do the same thing by using dijit.Declaration, see http://docs.dojocampus.org/dijit/Declaration.
It works for me when I use declare with the superclass inside of an array:
dojo.declare('myapp.mainToolbar', [ dijit.Toolbar ],
{
....
}
);
var x = new myapp.mainToolbar({ ... });
x.startup();
Which kind of violates the docs. It should take one Function or an array of Functions.

Categories

Resources