I have following json data.
{
"pendingTasksVOs" : [{
"groupName" : "LAST_MONTH",
"documents" : [{
"description" : "kvk1",
"uploadDate" : "1-12-2012"
}
]
}, {
"groupName" : "OLDER",
"documents" : [{
"description" : "kvk2",
"uploadDate" : "1-11-2012"
}, {
"description" : "kvk3",
"uploadDate" : "1-10-2012"
}, {
"description" : "kvk4",
"uploadDate" : "1-01-2012"
}
]
}
]
}
I want to show it in Sencha Touch list grouped by GroupName .
I want list to be in following format:
GoupName : Group1
-----------------------------
Description11 , UploadDate11 This should be separate clickable list row
-----------------------------
Description12 , UploadDate12 This should be separate clickable list row
-----------------------------
Description13 , UploadDate13 This should be separate clickable list row
-----------------------------
******************************
GoupName : Group2
-----------------------------
Description21 , UploadDate21 This should be separate clickable list row
-----------------------------
Description22 , UploadDate22 This should be separate clickable list row
-----------------------------
******************************
I am trying to use Sencha Touch List component. But I am not to get the list as per above requirements
//This is my store
var store = Ext.create('Ext.data.Store', {
model: 'Demo.model.DocumentList',
rootProperty: 'pendingTasksVOs',
autoLoad: true,
grouper: {
groupFn: function(record) {
if (record && record.data.title) {
return record.get('groupName');
} else {
return '';
}
}
}
});
//template for list item
var listTemplate = new Ext.XTemplate(
'<tpl for=".">',
'{groupName}</br>',
'<ul>',
'<tpl for="documents">',
'{description} {uploadDate} </br>',
'</tpl>',
'</ul>',
'</tpl>'
);
// Initialize the main view
Ext.getCmp("pendingTasksListId").add(Ext.create('Ext.List', {
fullscreen: true,
itemTpl: listTemplate,
store: store,
groupField:'description',
grouped: true
}));
//DocumentListModel is defined under /app/model/
Ext.define('Demo.model.DocumentList', {
extend: 'Ext.data.Model',
requires : ['Demo.model.Doc'],
config: {
fields: ['groupName', 'documents'],
hasMany : {
model : "Demo.model.Doc",
associationKey: 'documents'
},
proxy: {
type: 'rest',
url : "/getPendingTasks",
reader: {
type: 'json',
rootProperty : 'pendingTasksVOs'
}
}
}
}
//Document Model is defined under /app/model/
Ext.define('Demo.model.Doc', {
extend: 'Ext.data.Model',
config: {
fields: ['description', 'uploadDate'],
belongsTo: "Demo.model.DocumentList"
}
});
});
I am able to get the list item as follows:
GroupName,
Description11,UploadDate11
Description12,UploadDate12
But above whole content is clickable. I want to have each Description & UploadDate pair to be clickable.
Can anyone guide me on how can I achieve above stated requirement?
I got the solution for my question.
Create following custom json reader under /app/reader/ folder as CustomReader.js
Ext.define('Demo.reader.CustomReader', {
extend: 'Ext.data.reader.Json',
alias: 'reader.customReader',
getData: function(data) { // overriding
data = this.callParent(arguments);
var responseString = Ext.encode(data);
var json = JSON.parse(responseString);
var result = [];
Ext.each(json.pendingTasksVOs, function(entry) {
var groupName = entry.groupName;
Ext.each(entry.documents || [], function(document) {
result.push({
description : document.description,
uploadDate: document.uploadDate,
groupName: groupName
});
});
});
return result;
}
});
Doc model should be created at /app/model as follows as Doc.js
Ext.define('Demo.model.Doc', {
extend: 'Ext.data.Model',
config: {
fields: ['description','uploadDate','groupName']
}
});
Store can be created at /app/store folder
Store should use this custom reader as follows:
Ext.define("Demo.store.DocumentStore", {
extend:'Ext.data.Store',
requires:['Demo.model.Doc' , 'Ext.data.proxy.Rest', 'Demo.reader.CustomReader'],
id:'DocumentStore1',
config:{
model:'Demo.model.Doc',
autoLoad:true,
grouper:{
groupFn:function (record) {
if (record && record.data.groupName) {
return record.get('groupName');
} else {
return '';
}
}
},
proxy:{
type:'rest',
url:"/getPendingTasks",
reader:{
type:'customReader' //This is our custom reader
}
}
}
});
//Finally You can create the list as follows
Ext.create('Demo.store.DocumentStore');
// Initialize the main view
Ext.getCmp("pendingTasksListId").add(Ext.create('Ext.List', {
fullscreen:true,
itemTpl:'<div class="contact">{description} {uploadDate} {groupName} </div>',
store: 'DocumentStore1',
grouped:true
}));
Above gives me the list where I get separate row for each {description} {uploadDate} pair from the received json specified in question
Try this,
itemTpl: [
'<div>GroupName : {groupName}</div>',
'<div>',
'<ul>',
'<tpl for="documents">',
'<li>{description} , {uploadDate}</li>',
'</tpl>',
'</ul>',
'</div>',
].join('')
OR this,
itemTpl: [
'<div>GroupName : {groupName}</div>',
'<div>',
'<ul>',
'<tpl for="documents">',
'<li><div onclick="whateverYouWantToDo()">{description} , {uploadDate}</div></li>',
'</tpl>',
'</ul>',
'</div>',
].join('')
Related
I have a problem exporting with pdfhtml5. I have data on datatable with HTML and CSS style and want to visualize it on pdf or another plugin.
this is the variable exportOptions
var thisExportOptions = {
exportOptions: {
rows: function(idx, data, node) {
var checkedB = sontCoches(".dt-class-checkbox", "entireRow");
var dt = new $.fn.dataTable.Api('#datatable-configuration');
$(checkedB).each(function(i, v) {
dt.row(this).select();
});
var selected = dt.rows({ selected: true }).indexes().toArray();
if (selected.length === 0 || $.inArray(idx, selected) !== -1)
return true;
return false;
},
columns: ':visible'
}
};
and this for datatable id
var table = $('#datatable-configuration').DataTable({
"ajax": {
"url": "/backend/index.php",
"dataType": "json",
"type": "GET",
"data": {
"app": get ["app"],
"module": get ["module"],
"element": cElement,
"action": "serverside",
"actionParent": get ["action"],
//"get": get,
}
},
"buttons": [
$.extend(true, {}, thisExportOptions, { text: 'Imprimer', extend: 'print' }),
$.extend(true, {}, thisExportOptions, { text: 'PDF', extend: 'pdfHtml5' }),
{ extend: 'colvis', text: 'Export colonnes', className: 'btn-primary', columns: ":not(.notConcernedByColvis)" }
],
"fnStateLoad": function(oSettings) {
return JSON.parse(localStorage.getItem('dataTableStore'));
},
"stateSaveParams": function(settings, data) {
data.columns.forEach(function(column) {
delete column.visible;
});
}
)}
Php code
$datas[$key]['nom'] = "<span class='font-weight-bold text-success'>" . $brute->raison_sociale . "</span>";
$datas[$key]['nom'] .= (!empty($brute->rcs_siret)) ? "<br /><small><span class='font-weight-bold'>RCS : </span><span class='right'>" . $brute->rcs_siret . "</span></small>" : "";
$datas[$key]['autres'] = '';
And the pdf file is like this
Pdf export with no css and HTML no interpreted
Finally I found WkHtmlToPdf it can convert HTML page to PDF file.
It's very helpfull and free, PHP WkHtmlToPdf provides a simple and clean interface to ease PDF and image creation when you want only use free solution on your project.
For more information : https://github.com/mikehaertl/phpwkhtmltopdf
I have a JS view in which I am creating a sap.m.Table. It's "columns" are bound to a JSONModel. It's "items" are bound to ODataModel. I want to access the row data and the column name when I click on an Icon contained in the ColumnListItem.
View code:
createContent : function(oController) {
var oTable = new sap.m.Table("table1", {
width: "auto",
noDataText: "Please add rows to be displayed!"
}).addStyleClass("sapUiResponsiveMargin");
oTable.bindAggregation("columns", "Periods>/periods", function(sId, oContext) {
var sColumnId = oContext.getObject().period;
return new sap.m.Column({
hAlign: "Center",
vAlign: "Middle",
header: new sap.m.Text({
text: sColumnId
})
});
});
oTable.bindItems("zStatus>/StatusSet", function(sId, oContext) {
var row = new sap.m.ColumnListItem(sId, {
type : "Inactive",
cells: [
new sap.ui.core.Icon({
src: "sap-icon://delete",
hoverColor: "red",
activeColor: "red",
press: [oController.onDeleteIconPress, oController]
}),
new sap.m.Text({
text: "{zStatus>Description}"
}),
new sap.ui.core.Icon(sId, {
src: {
path: "zStatus>Status1",
formatter: function(status) {
switch(status) {
case "R":
return "sap-icon://sys-cancel";
case "G":
return "sap-icon://sys-enter";
case "Y":
return "sap-icon://notification";
default:
return "sap-icon://sys-help";
}
}
},
size: "1.5em",
press: [oController.onStatusIconPress, oController]
}) ]
});
return oTable;
}
In my controller I create an array, then a JSON model "Periods" from it and set it to this view. Odata model "zStatus" is defined in manifest file.
Controller code:
onInit : function() {
// array aPeriods is populated first then
var oPeriodsModel = new sap.ui.model.json.JSONModel();
oPeriodsModel.setData({
periods : aPeriods
});
this.getView().setModel(oPeriodsModel, "Periods");
},
onStatusIconPress : function(oEvent) {
// I can get the row data on icon press
// Problem 2: but how do I get the column name?
// I wanted to attach the column name to icon as customData but I could
// not access model attached to columns inside bindItems method
}
I managed to solve it myself.
Created an array in createContent. Filled it with column IDs in bindAggregation of columns and then used this array in bindItems method.
Then I can pass customData to icons.
Here is the code -
createContent : function(oController) {
var aColumns = []; // array to store column ids
var columnIndex = 0; // index to track
//more code
// create table oTable
oTable.bindAggregation("columns", "/columns", function(sId, oContext) {
var sColumnId = oContext.getObject().period;
if (sColumnId === "DeleteIcon") {
// this is always my first column
columnIndex = 0;
return new sap.m.Column({
hlign : "Begin",
vAlign : "Middle",
width : "2em",
header : new sap.m.Text({
text : ""
})
});
} else {
// add column ids to array
aColumns[columnIndex++] = sColumnId;
return new sap.m.Column({
hlign : "Center",
vAlign : "Middle",
header : new sap.m.Text({
text : sColumnId
})
});
}
});
oTable.bindItems("/rows", function(sId, oContext) {
var row = new sap.m.ColumnListItem({
new sap.m.Text({
text: "{Name}"
}),
new sap.ui.core.Icon(sId, {
src: "sap-icon://sys-help"
size: "1.5em",
press: [oController.onStatusIconPress, oController],
customData : [
// use column ids here
new sap.ui.core.CustomData({key: "column", value: aColumns[0]})
]
}),
});
return row;
}
}
Trying to 'parse/read' an external .json file on my typeahead code, but the .json file (which I cannot modify) looks like:
{"**cms_countries**":
[{"**cms_country**":
[{"**countrydisplayname**":"Afghanistan"}
,{"countrydisplayname":"Albania"} ,{"countrydisplayname":"Algeria"}
... ... ... ,{"countrydisplayname":"Zimbabwe"} ] } ,{"TotalRecords":
[ {"TotalRecords":"246"} ] } ] }
So, I think my problem is to know how to parse/read/assimilate/integrate/adopt this .json file, having
cms_countries ,
cms_country ,
and then, my countrydisplayname field on it. (have you seen the tree here ?)
This is my code:
$(document).ready(function() {
var searchablePlaces = new Bloodhound({
datumTokenizer : Bloodhound.tokenizers.obj.whitespace("countrydisplayname"),
queryTokenizer : Bloodhound.tokenizers.whitespace,
prefetch : 'countries.json',
remote : {
url : 'countries/%QUERY.json',
wildcard : '%QUERY',
filter : function(response) { return response.cms_country; }
},
limit : 10
});
searchablePlaces.initialize();
$('#remote .typeahead').typeahead(
{
hint : true,
highlight : true,
minLength : 2
},
{
name : 'countrydisplayname',
displayKey : "countrydisplayname",
source : searchablePlaces.ttAdapter()
})
});
But of course, it is not working:
ANY hint on how to organize my filter... ? or how to do to overcome my nested .json wrappers....
OK, I've got my code working now:
$(window).load(function(){
var movies = new Bloodhound({
limit: 10,
datumTokenizer: function (d) {
return Bloodhound.tokenizers.whitespace(d.value);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: 'countries.json',
filter: function (movies) {
return $.map(movies.cms_countries[0].cms_country, function (paises) {
return {
value: paises.countrydisplayname
};
});
}
}
});
// Initialize the Bloodhound suggestion engine
movies.initialize();
// Instantiate the Typeahead UI
$('.typeahead').typeahead(
{
hint: true,
highlight: true,
minLength: 1
},
{
//displayKey: 'value',
displayKey: function (toto) {
return toto.value;
},
source: movies.ttAdapter()
});
});
i have 100000 records in database...i have to display 50 at a time in enhanced grid when i scroll down next request goes to server and get next 50 like wise ......
i came across that this can be achieved by jsonRestStore....i tried with that but i am not getting that..how to use jsonRest for this purpose ????..plz sugggest me answer
my code is
require([
"dojo/_base/lang", "dojox/grid/EnhancedGrid",
"dojox/grid/enhanced/plugins/Search","dojox/grid/enhanced/plugins/Filter",
"dojox/grid/enhanced/plugins/Pagination","dojo/data/ItemFileWriteStore",
"dojo/store/JsonRest","dijit/form/Button","dojo/request/xhr", "dojo/dom",
"dojo/dom-construct", "dojo/json", "dojo/on", "dojox/grid/cells/dijit",
"dojo/domReady!"
], function(lang,EnhancedGrid,Search,Filter,Pagination,ItemFileWriteStore,JsonRest,Button,xhr, dom, domConst, JSON, on) {
xhr("//myipaddress/GridExample/string", {
handleAs : "json"
}).then(function(dataa){
/* domConst.place("<p>response: <code>" + JSON.stringify(dataa) + "</code></p>", "output"); */
/* domConst.place("<p>response: <code>" + JSON.stringify(dataa) + "</code></p>", "output"); */
var mydata=dataa;
var yourStore = new dojo.data.ItemFileWriteStore({
data: {
identifier: "sno",
/* items: mydata.aa */
items:mydata
}
});
grid = new EnhancedGrid({
id:'grid',
store : yourStore,
structure : layout,
rowSelector: '20px',
plugins: {
search:true,
pagination: {
pageSizes: ["50","100","500","1000"],
description: true,
sizeSwitch: true,
pageStepper: true,
gotoButton: true,
maxPageStep: 2,
position: "bottom"
},
filter: {
closeFilterbarButton: true,
ruleCount: 5,
itemsName: "rows"
}
}
});
grid.placeAt("myGrid");
grid.startup();
}, function(err) {
alert("error");
}, function(evt) {
});
var id=100000;
var addbutton = new Button({
onClick: function (){
id++;
/* alert(dojox.grid.scroller.firstVisibleRow);
alert(dojox.grid.scroller.lastVisibleRow); */
console.log(arguments);
grid.store.newItem({
sno:id,
sname:'san',
salary:'25000'
});
store.save();
grid.render();
}
}, "addRow");
var removebutton = new Button({
onClick: function (){
var items = grid.selection.getSelected();
alert(items);
if(items.length){
dojo.forEach(items, function(selectedItem){
if(selectedItem !== null){
store.deleteItem(selectedItem);
store.save();
}
});
}
grid.render();
}
}, "removeRow");
var updatebutton = new Button({
onClick: function (){
}
}, "updateRow");
var store1 = new JsonRest({
target: "http://localhost:7080/GridExample/string"
});
store.get(3).then(function(item){
alert(item);
});
});
I am sure you must have found answer to your question by now. But to help others, You haven't tied your JsonRest store (store1) to grid.
Here is example code that does this:
//jsonstore
var jsonStore = new dojo.store.Cache(new dojo.store.JsonRest({
target : "http://localhost:7080/GridExample/string",
idProperty : "id"
}), dojo.store.Memory({
idProperty : "id"
}));
grid = new dojox.grid.EnhancedGrid({
store : dataStore = dojo.data.ObjectStore({
objectStore : jsonStore
}),
id: "grid_id",
structure : layout,
rowSelector : '20px',
selectionMode : "single",
clientSort : true,
plugins : {
selector : true,
/**nestedSorting : true,**/
pagination : {
defaultPageSize : 20,
pageSizes : [ 20, 50, 100, "All" ],
description : true, // display the current position
sizeSwitch : true, // display the page length menu
pageStepper : true, // display the page navigation choices
gotoButton : true, // go to page button
/*page step to be displayed*/
maxPageStep : 4,
/*position of the pagination bar*/
position : "bottom"
}
}
}, "search_results_grid"); // make sure you have a target HTML element with this id
Two quick questions here... How can I use this example
http://try.sencha.com/touch/2.0.0/examples/list-search/
of a searchable list, but opened in a NEW view? The example has it defined as the main application in app.js, but I would like to use it in "FirstApp.view.searchlist"
I know the answer is pretty easy but I am still a young grasshoppa and need a push in the right direction.
Also, rather than pulling the data from the embedded store like the example, I would like to modify it to pull my data from my external/proxy JSON store, which is defined as follows:
Store:
Ext.define('FirstApp.store.StudentStore',{
extend:'Ext.data.Store',
config:{
autoLoad:true,
model:'FirstApp.model.people',
sorters: 'lastName',
proxy:{
type:'ajax',
url:'http://xxxyyyzzz.com/data/dummy_data.json',
reader:{
type:'json',
rootProperty:'results'
}
}
}
});
Model:
Ext.define('FirstApp.model.people', {
extend: 'Ext.data.Model',
config: {
fields: ['firstName', 'lastName' , 'image','status', 'phone','rank','attendance', 'discipline','recent']
}
});
So, how can I turn that example into a "view" inside my application, with my data store and model?
Any help is greatly appreciated! Thank you!
Jake
-----------UPDATE-------------
Ok fantastic. I was able to implement the search feature (stoked) by combining your methods with another tutorial I found. Now one more question...Seems so easy but it is tough! How can I open my new 'Details' view once an item is selected/clicked ??
Search list:
Ext.define('FirstApp.view.MainPanel', {
extend: 'Ext.dataview.List',
alias : 'widget.mainPanel',
config: {
store : 'Students',
itemTpl:
'<h1>{firstName:ellipsis(45} {lastName:ellipsis(45)}</h1>' ,
itemCls:'place-entry',
items: [
{
xtype: 'toolbar',
docked: 'top',
items: [
{
xtype: 'searchfield',
placeHolder: 'Search People...',
itemId: 'searchBox'
}
]
}
]
}
});
Details view (that I want to open when name is clicked from Search list/Mainpanel view):
Ext.define('FirstApp.view.Details',{
extend:'Ext.Panel',
xtype:'details',
config:{
layout:'fit',
tpl:'<div class="image_container"><img src="{image}"></div>' +
'<h1>{firstName:ellipsis(25)} {lastName:ellipsis(25)}</h1>'+
'<div class="status_container">{status:ellipsis(25)}</div> '+
'<div class="glance_container"> <div class="value_box"><div class="value_number"> {rank:ellipsis(25)}</div> <p class="box_name">Rank</p> </div> <div class="value_box"><div class="value_number"> {attendance:ellipsis(25)}</div> <p class="box_name" style="margin-left: -10px;">Attendance</p> </div> <div class="value_box"><div class="value_number">{discipline:ellipsis(25)}</div> <p class="box_name" style="margin-left: -4px;">Discipline</p> </div> <div class="value_box"><div class="value_number"> {recent:ellipsis(25)}</div> <p class="box_name">Recent</p> </div> </div> '+
'<h2>Phone:</h2> <div class="phone_num"><p>{phone:ellipsis(25)}</p></div>'+
'<h3>Some info:</h3><p>Round all corners by a specific amount, defaults to value of $default-border-radius. When two values are passed, the first is the horizontal radius and the second is the vertical radius.</p>',
scrollable:true,
styleHtmlContent:true,
styleHtmlCls:'details'
}
})
Search Controller:
Ext.define('FirstApp.controller.SearchController', {
extend : 'Ext.app.Controller',
config: {
profile: Ext.os.deviceType.toLowerCase(),
stores : ['StudentStore'],
models : ['people'],
refs: {
myContainer: 'MainPanel',
placesContainer:'placesContainer'
},
control: {
'mainPanel': {
activate: 'onActivate'
},
'mainPanel searchfield[itemId=searchBox]' : {
clearicontap : 'onClearSearch',
keyup: 'onSearchKeyUp'
},
'placesContainer places list':{
itemtap:'onItemTap'
}
}
},
onActivate: function() {
console.log('Main container is active');
},
onSearchKeyUp: function(searchField) {
queryString = searchField.getValue();
console.log(this,'Please search by: ' + queryString);
var store = Ext.getStore('Students');
store.clearFilter();
if(queryString){
var thisRegEx = new RegExp(queryString, "i");
store.filterBy(function(record) {
if (thisRegEx.test(record.get('firstName')) ||
thisRegEx.test(record.get('lastName'))) {
return true;
};
return false;
});
}
},
onClearSearch: function() {
console.log('Clear icon is tapped');
var store = Ext.getStore('Students');
store.clearFilter();
},
init: function() {
console.log('Controller initialized');
},
onItemTap:function(list,index,target,record){ // <-----NOT WORKING
this.getPlacesContainer().push({
xtype:'details',
store:'Students',
title:record.data.name,
data:record.data
})
}
});
Good question. I assume you are trying to build a List or dataview. The key here is to give your store a 'storeId'. I have modified your store below:
Ext.define('FirstApp.store.StudentStore',{
extend:'Ext.data.Store',
config:{
storeId: 'Students', // Important for view binding and global ref
autoLoad:true,
model:'FirstApp.model.people',
sorters: 'lastName',
proxy:{
type:'ajax',
url:'http://xxxyyyzzz.com/data/dummy_data.json',
reader:{
type:'json',
rootProperty:'results'
}
}
}
});
Then inside your view, you reference the store to bind to. Here is an example List view from one of my applications. Notice the config object has 'store' which references our above store:
Ext.define('app.view.careplan.CarePlanTasks', {
extend: 'Ext.dataview.List',
xtype: 'careplanTasks',
requires: [
'app.view.template.CarePlan'
],
config: {
store: 'Students', // Important! Binds this view to your store
emptyText: 'No tasks to display',
itemTpl: Ext.create('app.view.template.CarePlan'),
},
constructor : function(config) {
console.log('CarePlan List');
this.callParent([config]);
}
});
Now that you have a storeId, you can access this store anywhere in your application by doing the following:
Ext.getStore('Students')
You can load records from your server by calling the load method as well:
Ext.getStore('Students').load();
You can do this anywhere in your application, but typically it's best to do in your controllers.
Hope this helps.
======= Updates to your updates ======
So looking at your code I think you need to modify your List view and the controller. Give 'FirstApp.view.MainPanel' an xtype: 'MainPanel'. Next modify your controller config as follows:
config: {
profile: Ext.os.deviceType.toLowerCase(),
stores : ['StudentStore'],
models : ['people'],
refs: {
mainPanel: 'MainPanel', // set the object KEY to the name you want to use in the control object and set the VALUE to the xtype of the view
placesContainer:'placesContainer'
},
control: {
'mainPanel': { // this matches the key above, which points to your view's xtype
activate: 'onActivate',
itemtap: 'onItemTap' // listen for the item tap event on this List
},
'mainPanel searchfield[itemId=searchBox]' : {
clearicontap : 'onClearSearch',
keyup: 'onSearchKeyUp'
},
'placesContainer places list':{
itemtap:'onItemTap'
}
}
},