How to implement jqGrid with Marionette? - backbone.js

I am trying to render jqGrid in my Marionette application, everything goes fine until I cannot find the way to render the pager.
I am using Handlebars that holds the template, this is the code:
hb template:
<script id='llantas_grid_tmpl' type='text/x-handlebars-template'>
<table id='llantas_catalog_list'></table>
<div id="llantas_catalog_pager">pager</div>
</script>
layout...
ui: {
table: '#llantas_catalog_list',
pager: '#llantas_catalog_pager'
},
onRender: function(){
var table = this.ui.table,
pager = this.ui.pager;
table
.jqGrid({
url: '/llantas',
datatype: "json",
colNames:['Id','Orden De Compra', 'Marca', 'Medida', 'Modelo'],
colModel:[
{name:'id',index:'id', width:55},
{name:'ordencompra',index:'ordencompra', width:90},
{name:'marca',index:'marca', width:90},
{name:'medida',index:'medida', width:90},
{name:'modelo',index:'modelo', width:90}
],
rowNum:10,
rowList:[10,20,30],
pager: '#llantas_catalog_pager',
width:1060,
height:375,
sortname: 'id',
viewrecords: true,
sortorder: "desc",
caption:"<h3>Catalogo llantas<h3>"
});
table
.jqGrid('navGrid','#llantas_catalog_pager',{edit:false,add:false,del:false});
}
is there a way to set the pager placeholder into the jqGrid as object?
like this:
table
.jqGrid('navGrid',pager,{edit:false,add:false,del:false});
EDIT: PLEASE ANSWER ONLY IF YOU KNOW BACKBONE MARIONETTE AND JQGRID.

In a word, No.
jqGrid does a check to make sure it is a string,
if(!$t.grid || typeof elem !== 'string') {return;}
You would need to modify the jqGrid source.

I found the way to make it work:
Once the child view (the one I was trying to render with jqGrid) has been rendered and displayed in the region of the main view I just search for the template table selector and pass the pager id inside the jqGrid pager option.
main layout...
onRender: function(){
// llantasGridView is the view holding only the template without the jqGrid (I erased everything)
var llantasGridView = new LlantasGrid.View();
// table_container is the region that will hold the llantasGridView template
this.table_container.show( llantasGridView );
// once is rendered I search for the table
var table = llantasGridView.$el.find('#llantas_catalog_list');
// here I pass the jqGrid
table
.jqGrid({
url: G.API + '/llantas',
datatype: "json",
colNames:['Id','PO'...
pager: '#llantas_catalog_pager', // pager for grid is now being displayed
...

Related

How to use .cshtml razor file as ui-grid celltemplate?

In my ASP.net MVC web project, I am using ANgularJS ui-grid for better data display option.
In the other razo view pages I have used partial view load
<partial name="TestPartialView" model="data.TestPartialData" />
Now in the ui-grid, in a column I also want to use the partial view.
```$scope.columns = [
{
name: 'TestColumn',
field: '..xxx',
width: '30%',
cellTemplate: 'Templates/TestPartialView.cshtml'
},] ```
But I really dont know how to do this. Also in my TestPartialView.cshtml, I need to inject a model class.
As a current alternative, I have defined the template again in the javascript file.But I want reuse the template.
Any idea?
Update:
So the above screenshot is my scenario. I will have a grid column statistics. And in the cell I will show bar chart based on some row specific model data.
Yes I have done this (as seen on the picture) with column definition.
Now the similar bar chart I have used a .cshtml file where a model class is passed and the view is loaded partially.
I want to reuse the partial view her in the grid also.
I think you can create a Controller to return your target View. And then you call this endpoint to obtain the view as the response and add it into your cellTemplate.
$http.get("https://localhost:44391/Home/GetTemplateFromPartial")
.then(function(response) {
$scope.columns = [
{
name: 'TestColumn',
field: '..xxx',
width: '30%',
cellTemplate: $sce.trustAsHtml(response.data)
}];
console.log($scope.columns);
});
The Controller will return IActionResult
public IActionResult GetTemplateFromPartial()
{
LocalMallUser user = new LocalMallUser
{
id = 1,
age = 18,
user_name = "test_user"
};
return PartialView("_SayHello", user);
}
_SayHello.cshtml:
#model WebApplication1.Models.LocalMallUser
<h1>#Model.user_name</h1>
<h2>#Model.age</h2>

How to prevent Kendo MultiSelect from losing values after editing in a grid template?

I have a grid that displays a comma-separated list of values, and it has an array that gets used in a template editor for the grid. (On the server, I transform the comma-separated list to an array for the Kendo multiselect AngularJS directive). I have almost everything working: display, edit, and adding values in the multiselect.
There's just one weird thing happening: after I add a value in the multiselect, click Save in the editor, and reopen the editor, the multiselect then only displays one of the most-recently entered values. I know that the values are there and going through the pipeline, because the values make it into the database. I can refresh the page, open the editor, and all the values display in the multiselect correctly, including the one I just added.
It's as if kendo "forgets" most of the values when I reopen the editor. How can this be prevented? Does the MultiSelect need to be rebound to the values? If so, how?
I have tried adding this onChange event, but it had no effect. I've added valuePrimitive to no effect. I tried specifying k-rebind, but it caused an error.
Here's the directive being used in the text/x-kendo-template:
<select kendo-multi-select
id="zipCode"
k-placeholder="'Enter zip codes...'"
style="width: 225px"
k-on-change="dataItem.dirty=true"
k-auto-bind="false"
k-min-length="3"
k-enforce-min-length="true"
k-data-source="options.zipCodeDataSource"
k-data-text-field="'text'"
k-filter="'startsWith'"
k-filtering="options.zipCodeFiltering"
k-no-data-template="'...'"
k-ng-model="dataItem.zipArray"
k-highlight-first="true" />
And this is the DataSource:
options.zipCodeDataSource = new kendo.data.DataSource({
severFiltering: true,
transport: {
read: {
url: serviceUrl + "ZipCode/Get",
type: "GET",
dataType: "json",
contentType: jsonType,
data: function (e) {
// get your widget.
let widget = $('#zipCode').data('kendoMultiSelect');
// get the text input
let filter = widget.input.val();
// what you return here will be in the query string
return {
filter: filter
};
}
},
},
schema: {
data: "data",
total: "Count",
model:
{
id: "text",
fields: {
text: { editable: false, defaultValue: 0 },
}
},
parse: function (response) {
return response;
}
},
error: function (e) {
}
});
If I display {{dataItem.zipArray}} in a <pre> all of the expected values are there.
I wonder if something needs to be added to the edit event handler in the kendo grid definition, but I'm not sure what it would be. I've had to do binding like that for the dropdownlist directive.
edit: function (e) {
if (e.model.marketId === 0) {
e.container.kendoWindow("title", "Add");
} else {
e.container.kendoWindow("title", "Edit");
}
// re-bind multi-select here??
// These two lines actually cause the multiselect to lose pre-existing items in dataItem.zipArray
// var multiselect = kendo.widgetInstance(angular.element('#zipCode'));
// multiselect.trigger('change');
}
...
Update:
This dojo demonstrates the issue.
Run the dojo
Edit the first record in the Contracts grid
Add a zip code such as 22250
Click Save
Then click Edit on the first row again
Only zip code 22250 is displayed in the editor
Also, I notice that if I change k-min-length="3" to k-min-length="1", then the issue goes away. But in the scenario I'm working on, it needs to be 3.
This seems to be an issue with kendo itself. Back then this issue was reported here.
Ok based on the reply from telerik, this issue has been fixed in 2017 R3 SP1 release (2017.3.1018). You can verify it by using this updated dojo example:
http://dojo.telerik.com/IREVAXar/3

ExtJS 4.2.1 Grid view overriden with custom XTemplate shows nothing

I am working on a switch from version 4.1.1 to 4.2.1 and finally I need to fix hopefully the last bug. We have a gridview with view being overriden by simple (?) Ext.XTemplate, as follows:
Ext.define('view.monitoring.Event',
{
extend: 'Ext.view.View',
alias: 'widget.default_monitoring_event',
itemSelector: '.monitoring-thumb-fumb',
tplWriteMode: 'overwrite',
autoWidth: true,
initComponent: function()
{
var tplPart1 = new Ext.XTemplate('<SOME HTML 1>');
var tplPart2 = new Ext.XTemplate('<SOME HTML 2>');
var tplPart3 = new Ext.XTemplate('<SOME HTML 3>');
var tplPart4 = new Ext.XTemplate('<SOME HTML 4>');
this.tpl = new Ext.Template('<BUNCH OF HTML AND TPL and TPL INSIDE TPL',
callFunc1: function(data) { /* do something with tplPart1 */ },
callFunc2: function(data) { /* do something with tplPart2 */ },
callFunc3: function(data) { /* do something with tplPart3 */ },
callFunc4: function(data) { /* do something with tplPart4 */ },
);
this.callParent(arguments;
}
}
This view is set for the grid in this way:
Ext.define('view.monitoring.WeeklyOverview',
{
extend: 'Ext.grid.Panel',
alias: 'widget.default_monitoring_weeklyoverview',
layout: 'border',
title: Lang.translate('event_monitoring_title'),
overflowX: 'hidden',
overflowY: 'auto',
initComponent: function()
{
//...
this.view = Ext.widget('default_monitoring_event', {
store: Ext.create('store.monitoring.Rows')
});
//...
}
}
Then in controller onRender the stores gets populated (the store of the grid is AJAX, loads the data and passes them to a memory store of the view). In ExtJS 4.1.1 this is working properly, data are loaded and the template is parsed and HTML is displayed containing the data.
But after the switch to 4.2.1 the HTML is no longer filled with the data and nothing is displayed but an empty HTML table (which appears as like nothing would be rendered). As there is at least some part of HTML but no data, I guess the problem might be with the data being applied for the template.
Does anybody know what might be/went wrong?
UPDATE: After debugging and the custom view template simplification I have found out, that even the custom view has set it's own store with it's own root for the data returned, it ignores that setting and simply loads the data for the store of the Ext.grid.Panel component. The AJAX response looks like:
{
user: {},
data: [
0: { ... },
1: { ... },
...
],
rows: [
0: { ... },
1: { ... },
...
]
}
Here the data should be used for Ext.grid.Panel component and the rows should be then populated by the custom view (configured with Ext.XTemplate). Seems like for the children views always the parent's store's root element is returned. Any way how to workaround this behaviour and make the custom view to use it's own store???
Finally found a solution.
The problem was that after the main grid.Panel loaded the data it distributed them also to it's (sub)view. After that even I had manually loaded the right data into this custom XTemplate, it needed to also manually override previously rendered view.
In my controller (init -> render) I needed to do this:
var me = this;
this.getMainView().store.load({
params: params || {},
callback: function(records, operation, success) {
// this line was already there, working properly for ExtJS 4.1.1, probably is now useless for ExtJS 4.2.1 with the next line
me.getCustomView().store.loadRawData(this.proxy.reader.rawData);
// I had to add this line for ExtJS 4.2.1...
me.getCustomView().tpl.overwrite(me.getCustomView().el, this.proxy.reader.rawData.rows);
}
});
This is kinda strange as I thought that with a definition within a custom view (see my question above)
tplWriteMode: 'overwrite',
it should just automatically overwrite it's view...

"each" method in extjs data store

So, I got a data store in my code that I'm loading in a function. In that store I want to use the each method to append each record to the body of a panel in a certain format.
What I'm trying to figure out is how to use this "each" method. Has anyone ever had to use it before? I'm relatively new to functions and programming in general so I'm trying to figure out what the "fn" and "scope" are relative to my own code.
Any help would be awesome if anyone has used this method in the ExtJS framework before.
Use Dataview for your case. Add the store and the XTemplate to your dataview and add this dataview as an item to your panel. It will be something like this:
this.store = new Ext.data.JsonStore({
url : 'myproxy.php',
baseParams : {
action : 'get_basket_files'
},
root : 'rows',
id : 'filename',
fields : ['filename', 'filepath', 'filesize', 'fileclass']
});
this.filesTemplate = new Ext.XTemplate(
'<div class="files_container"><tpl for=".">',
'<div id="{filename}" class="basket-fileblock"><div class="{fileclass}"></div>',
'<div class="filetext">{filename}</div></div> ','</tpl></div>');
this.filesTemplate.compile();
this.filesDataView = new Ext.DataView({
itemSelector : 'div.basket-fileblock', //Required
style : 'overflow:auto',
multiSelect : true,
store : this.store,
tpl : this.filesTemplate
});
var panel = new Ext.Panel({
layout : 'fit',
items : [this.filesDataView]
});
Here XTemplate is the HTML template of each of the items. Have a look at the ExtJS documentation which provides a number of examples for XTemplate.
And for an example, ExtJS each function can be used this way:
Suppose an array of items is myItems. So,
Ext.each(myItems, function(eachItem){
//Do whatever you want to do with eachItem
}, this);
It sounds like you want an Ext.DataView.
DataView use Template or XTemplate to create a rendering of data in a store.
So you instantiate a configured dataview, including a reference to your store, and the template to use, and add that DataView to your panel.

Extjs Dynamic Grid

I'm trying to create a dynamic grid using ExtJS. The grid is built and displayed when a click event is fired then an ajax request is sent to the server to fetch the columns, records and records definition a.k.a store fields.
Each node could have different grid structure and that depends on the level of the node in the tree.
The only way I came up with so far is :
function showGrid(response, request) {
var jsonData = Ext.util.JSON.decode(response.responseText);
var grid = Ext.getCmp('contentGrid' + request.params.owner);
if (grid) {
grid.destroy();
}
var store = new Ext.data.ArrayStore({
id: 'arrayStore',
fields: jsonData.recordFields,
autoDestroy: true
});
grid = new Ext.grid.GridPanel({
defaults: {
sortable: true
},
id: 'contentGrid' + request.params.owner,
store: store,
columns: jsonData.columns,
//width:540,
//height:200,
loadMask: true
});
store.loadData(jsonData.records);
if (Ext.getCmp('tab-' + request.params.owner)) {
Ext.getCmp('tab-' + request.params.owner).show();
} else {
grid.render('grid-div');
Ext.getCmp('card-tabs-panel').add({
id: 'tab-' + request.params.owner,
title: request.params.text,
iconCls: 'silk-tab',
html: Ext.getDom('grid-div').innerHTML,
closable: true
}).show();
}
}
The function above is called when a click event is fired
'click': function(node) {
Ext.Ajax.request({
url: 'showCtn',
success: function(response, request) {
alert('Success');
showGrid(response, request);
},
failure: function(results, request) {
alert('Error');
},
params: Ext.urlDecode(node.attributes.options);
}
});
}
The problem I'm getting with this code is that a new grid is displayed each time the showGrid function is called. The end user sees the old grids and the new one. To mitigate this problem, I tried destroying the grid and also removing the grid element on each request, and that seems to solve the problem only that records never get displayed this time.
if (grid) {
grid.destroy(true);
}
The behaviour I'm looking for is to display the result of a grid within a tab and if that tab exists replaced the old grid.
Any help is appreciated.
When you are trying to add your grid to the tab like this:
html:Ext.getDom('grid-div').innerHTML,
Ext is not aware of it being a valid grid component. Instead, you are simply adding HTML markup that just happens to look like a grid, but the TabPanel will not be aware that it is a grid component.
Instead you should add the grid itself as the tab (a GridPanel is a Panel and does not need to be nested into a parent panel). You can do so and also apply the needed tab configs like this:
Ext.getCmp('card-tabs-panel').add({
Ext.apply(grid, {
id: 'tab-' + request.params.owner,
title: request.params.text,
iconCls: 'silk-tab',
closable: true
});
}).show();
BTW, constantly creating and destroying grids is not an ideal strategy if you can avoid it. It might be better to simply hide and re-show grids (and reload their data) based on which type of grid is needed if that's possible (assuming the set of grid types is finite).
A potential option is to use the metaData field on the JsonStore that allows dynamic reconfiguring of the grid columns as per new datasets.
From
One of the most helpful blog posts about this that Ive found is this one:
http://blog.nextlogic.net/2009/04/dynamic-columns-in-ext-js-grid.html and the original info is well documented at http://docs.sencha.com/ext-js/3-4/#!/api/Ext.data.JsonReader

Resources