How to send JSON using JSF2 Primefaces Request Context to Highchart? - json
Hi I've been strugling with this for hours, I want to send my POJO in JSON format using Primefaces Request Context to a Highchart inside my JSF to update its value.
Basically I am following this solution of #Bhesh Gurung from his own stackoverflow question
but I cant seem to make it work. Right now it is throwing a:
Cannot find component with identifier "pieData" referenced from "j_idt31".
I want to sucessfully create a highchart using the JSON data through the Primefaces Request Context. Please help Thanks in advance.
This are my codes below
#ManagedBean
#ViewScoped
public class PieDataProvider {
public void retrievePieData() {
List<String> categories = new ArrayList<String>();
categories.add("Electronic");
categories.add("Food");
categories.add("Liguor");
categories.add("Stationary");
categories.add("Mechanical");
List<Integer> itemCounts = new ArrayList<Integer>();
itemCounts.add(5);
itemCounts.add(20);
itemCounts.add(1);
itemCounts.add(50);
itemCounts.add(10);
RequestContext reqCtx = RequestContext.getCurrentInstance();
reqCtx.addCallbackParam("categories", new Gson().toJson(categories));
reqCtx.addCallbackParam("itemCounts", new Gson().toJson(itemCounts));
System.out.println(categories);
}
}
My xhtml page5.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition template="/template/common/commonLayout.xhtml">
<ui:define name="content">
<h:head>
<script type="text/javascript">
src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"
src="http://code.highcharts.com/highcharts.js"
src="http://code.highcharts.com/modules/exporting.js"
</script>
<script type="text/javascript">
function feedPieData(xhr, status, args) {
var categories = eval('(' + args.categories + ')');
var itemCounts = eval('(' + args.itemCounts + ')');
options.xAxis.categories = categories;
var series = {
data : []
};
series.name = new Date().toString();
series.data = itemCounts;
options.series = [ series ];
chart = new Highcharts.Chart(options);
}
</script>
</h:head>
<h:body>
<p:commandLink action="#{pieDataProvider.retrievePieData}"
oncomplete="feedPieData(xhr, status, args);" value="Pie chart demo"
update="pieData" />
</h:body>
</ui:define>
<ui:define name="footer">
<h2>This is page5 Footer</h2>
</ui:define>
</ui:composition>
UPDATE: MODIFIED XHTML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:body>
<ui:composition template="/template/common/commonLayout.xhtml">
<ui:define name="content">
<h:head>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
$('#container')
.highcharts(
{
chart : {
plotBackgroundColor : null,
plotBorderWidth : null,
plotShadow : false
},
title : {
text : 'Most used words, 2010'
},
tooltip : {
pointFormat : '{series.name}: {point.percentage}',
percentageDecimals : 1
},
plotOptions : {
pie : {
allowPointSelect : true,
cursor : 'pointer',
dataLabels : {
enabled : true,
color : '#000000',
connectorColor : '#000000',
formatter : function() {
return '<b>'
+ this.point.name
+ '</b>: '
+ this.percentage
//+ ' %'
;
}
}
}
},
series : [ {
type : 'pie',
name : 'Browser share',
data : [ [ 'Red', 45.0 ],
[ 'Orange', 26.8 ], {
name : 'Yellow',
y : 12.8,
sliced : true,
selected : true
}, [ 'Green', 8.5 ],
[ 'Blue', 6.2 ],
[ 'Violet', 0.7 ] ]
} ]
});
});
</script>
<script type="text/javascript">
function feedPieData(xhr, status, args) {
var categories = JSON.parse(args.categories);
var itemCounts = JSON.parse(args.itemCounts);
var series = {
data : []
};
options.series[0].data.length = 0;
series.data = categories;
series.data = itemCounts;
options.series = [ series ];
chart = new Highcharts.Chart(options);
}
</script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
</h:head>
<h:body>
<div id="container"
style="min-width: 400px; height: 400px; margin: 0 auto"></div>
<h:form>
<p:commandLink action="#{pieDataProvider.retrievePieData}"
oncomplete="feedPieData(xhr, status, args);"
value="Pie chart demo" />
</h:form>
</h:body>
</ui:define>
<ui:define name="footer">
<h2>This is page5 Footer</h2>
</ui:define>
</ui:composition>
</h:body>
</html>
You seem to fail to understand that Highcharts is a JavasScript environment that runs solely on the client, while PrimeFaces/JSF is on the server side and they act in this context simply as HTML, CSS and JavaScript code generator.
In your particular case, PrimeFaces is simply used to send data from the server to the client via RequestContext. After AJAX call completes and effectively, serialized data is received by the client, you call a JavaScript function that creates a Highcharts JS component entirely on the client from the received data.
All in all, it yields us with the following setup.
** The view elements **
<h:form>
<p:commandLink action="#{pieDataProvider.retrievePieData}"
oncomplete="feedPieData(xhr, status, args);"
value="Generate pie chart" />
</h:form>
** The JavaScript **
<script type="text/javascript">
function feedPieData(xhr, status, args) {
var categories = JSON.parse(args.categories);//serialized data from server
var itemCounts = JSON.parse(args.itemCounts);//serialized data from server
//next you create the chart and show it
}
</script>
** The action method **
public void retrievePieData() {
List<String> categories = generateCategories();
List<Integer> itemCounts = generateItems();
RequestContext reqCtx = RequestContext.getCurrentInstance();
reqCtx.addCallbackParam("categories", new Gson().toJson(categories));//additional serialized data to be sent
reqCtx.addCallbackParam("itemCounts", new Gson().toJson(itemCounts));//additional serialized data to be sent
}
Related
print reflowed p:dataTable on normal format using p:printer
I have the following code <p:dataTable id="table" reflow="true"> ... </p:dataTable> <p:commandButton> <p:printer target="table" /> <p:commandButton> is there a way to print the table with its normal format even if it is in reflow mode(each row as a stack)?
This is what I end up doing I created a function to modify jquery print function to format my table as I wanted it before print it function formatTableBeforePrint() { $.fn.jqprint = (function() { var cached_function = $.fn.jqprint; return function(d) { $.fn.jqprint.defaults = { debug : false, importCSS : true, printContainer : true, operaSupport : true }; var tables = $('.ui-datatable-reflow'); $(".ui-datatable-reflow .ui-datatable-data td .ui-column-title").addClass('noprint'); tables.removeClass('ui-datatable-reflow'); var result = cached_function.apply(this, arguments); tables.addClass('ui-datatable-reflow'); return result; }; })(); } and then called that function from my p:commandButton <p:commandButton onclick="formatTableBeforePrint()"> <p:printer target="table" /> <p:commandButton>
Kendo Template, address certain element of json array
Hi I'm trying to programm my first app in Icentium. I want to store wisdoms in a json array. Depending on your level you get a new wisdom. Unfortunately I don't know why it is shwoing the whole json array. This is the lessons.js (function(global) { var LessonsViewModel, app = global.app = global.app || {}; LessonsViewModel = kendo.data.ObservableObject.extend({ lessonsDataSource: null, init: function () { var that = this, dataSource; kendo.data.ObservableObject.fn.init.apply(that, []); dataSource = new kendo.data.DataSource({ transport: { read: { url: "data/lessons/lessons.json", dataType: "json" } } }); that.set("lessonsDataSource", dataSource); } }); app.lessonsService = { viewModel: new LessonsViewModel() }; This is the view <!--Lessons--> <div id="tabstrip-lesson" data-role="view" data-title="Lektion" data-model="app.lessonsService.viewModel"> <div class="lesson"> <div class="separator"> <div class="dark"></div> <div class="light"></div> </div> <ul class="forecast-list" data-role="listview" data-bind="source: lessonsDataSource" data-template="lessons-template"><!-- Das unten stehende Kendo Template wird hier eingefügt--> </ul> </div> </div> <!--Lessons Kendo Template für oben--> <script type="text/x-kendo-tmpl" id="lessons-template"> <div> <h1>${dojoroom}</h1> <p>${text}</p><!-- Text aus Json File wird ausgelesen--> </div> </script> This is my json array: [ { "dojoroom": "Dojo - First Room", "text": "Bla bla bla!" }, { "dojoroom": "Dojo - Second Raum", "text": "More Bla" } ]
So far what I tried according to the Kendo Documenation (http://docs.kendoui.com/api/framework/datasource): LessonsViewModel = kendo.data.ObservableObject.extend({ lessonsDataSource: null, init: function () { var that = this, dataSource; kendo.data.ObservableObject.fn.init.apply(that, []); dataSource = new kendo.data.DataSource({ transport: { read: { url: "data/lessons/lessons.json", dataType: "json" } } }); that.set("lessonsDataSource", dataSource.at(0)); } }); But this doesn't show anything at all. I also tried dataSource[0] and the same approaches in the view. And dataSource.fetch(function(){ var dojo = dataSource.at(0); that.set("lessonsDataSource", dojo); });
Pass data from controller to view via JSONResult
I'd like to send ViewModel from controller to view in JSON format. Controller: public ActionResult Select(int pageLimiter) { var viewModel = new ArticlesViewModel { Articles = this.Service.GetArticles(0, 0, 0), ArticlesTotal = this.Service.CountArticles(0), Pages = new List<string> { "1", "2", "3" } }; return Json(viewModel, JsonRequestBehavior.AllowGet); } View: <ul class="articleList"> #if (#Model != null) { foreach (var article in #Model.Articles) { <li> <header>#article.Title</header> <nav> <span>#article.AuthorName</span> | <time>#article.PublishDate.ToString("")</time> | <span>#article.CategoryName</span> | <span>#article.Comments Comments</span> </nav> <section> #article.Content </section> </li> } } </ul> <script type="text/javascript"> $(document).ready(function () { GetArticles(5); $("#selectPager").change(function () { var selectedItem = ""; $("#selectPager option:selected").each(function () { selectedItem = $(this).text(); }); GetArticles(selectedItem); }); }); function GetArticles(pageLimitValue) { $.ajax( { url: "/Articles/Select", dataType: "json", data: { pageLimiter: pageLimitValue }, async: true, beforeSend: function () { alert("before"); }, complete: function (data) { #Model = SOME_MAGIC_TRICKS } }); } As you can see, in the complete event are words SOME_MAGIC_TRICKS. In this place I'd like to set #Model obtained from controller. Is it possible at all? How to insert data from ajax result to view model (it's null by default)?
You are trying to modify server variable from client's code. It's not possible. If you want to re-render your page's content on complete, you may render <ul class="articleList"> with PartialView and return same partial view instead of JsonResult. Further, oncomplete handler will update your <ul class="articleList"> with returned content.
You can send data doing serialize it may be like: public ActionResult Select(int pageLimiter) { var viewModel = new ArticlesViewModel { Articles = this.Service.GetArticles(0, 0, 0), ArticlesTotal = this.Service.CountArticles(0), Pages = new List<string> { "1", "2", "3" } }; string myjsonmodel = new JavaScriptSerializer().Serialize(viewModel ); return Json(jsonmodel = viewModel, JsonRequestBehavior.AllowGet); } dont forget using using System.Web.Script.Serialization; Edit: To deserialize object try this: #{ JavaScriptSerializer jss= new JavaScriptSerializer(); User user = jss.Deserialize<User>(jsonResponse); }
Data-binding MVC-4 to a Knockout.js foreach
We have a form in our web application that, in one place, asks the user to enter a list of values. We wrote this part of the form using Razor and knockout.js so that there is a textbox for each value of the list, similar to this tutorial. How can we data-bind these textboxes to our MVC model? Here is our form: #model OurProject.Models.Input.InputModel #{ ViewBag.Title = "Input"; } <h2> Inputs</h2> <div id="inputKOApp"> #using (Html.BeginForm()) { <!-- snip - lots of part of our form that work correctly --> <div class="row-fluid"> <div class="control-group"> <div class="span8 control-label"> #Html.LabelFor(model => model.POSTransactionCodes) </div> <div class="controls"> <!-- These are the textboxes we would like to bind to MVC --> <ul class="pull-right" data-bind="foreach: POSTransactionCodes"> <li> <input data-bind="value: code" /> Delete</li> </ul> <button class="pull-right" data-bind="click: addPOSTransactionCode"> Add another POS Transaction Code</button> #Html.ValidationMessageFor(model => model.POSTransactionCodes, null, new { #class = "help-inline" }) </div> </div> </div> <!-- snip - more cshtml that is irrelevant to the problem --> </div> <input type="submit" value="Submit" /> } </div> <script type="text/javascript" src='~/Scripts/jquery-1.8.2.min.js'></script> <script type="text/javascript" src='~/Scripts/knockout-2.1.0.js'></script> <script type="text/javascript" src='~/Scripts/OP/OP.js'></script> <script type="text/javascript" src='~/Scripts/OP/Input/OP.Input.Input.Form.js'></script> <script type="text/javascript" src='~/Scripts/OP/Input/OP.Input.Input.Data.js'></script> <script type="text/javascript"> var inputApp = $('#inputKOApp')[0]; OP.Input.Form.init(inputApp); </script> Here is our knockout.js script, OP.Input.Input.Form.js: extend(OP, 'OP.Input.Form'); OP.Input.Form = function (jQuery) { var TransactionCodeView = function () { var self = this; self.code = ""; }; //The ViewModel for the page var ViewModel = function () { var self = this; //Fields /* snip - lots of fields that work as expected */ self.POSTransactionCodes = ko.observableArray([]); //is a list of transaction codes //Set up with initial data /* I'm guessing that we won't need this function anymore since MVC will populate * everything for us, but I'll leave it in until I'm far enough along to know * I won't need to gut lots of stuff */ self.initialize = function () { var c = function (data, status, response) { /* snip - lots of fields that work as expected */ if (status === "success") { if(data.POSTransactionCodes != null) ko.utils.arrayPushAll(self.POSTransactionCodes, data.POSTransactionCodes); self.POSTransactionCodes.valueHasMutated(); } else { } }; OP.Input.Data.GetInput(c); } //When saving, submit data to server self.save = function (model) { var c = function (data, status, response) { if (status === "success") { } else { } }; OP.Input.Data.SaveInput(model, c); } //Modifying POSTransactionCodes array self.removePOSTransactionCode = function (POScode) { self.POSTransactionCodes.remove(POScode); } self.addPOSTransactionCode = function () { self.POSTransactionCodes.push(new TransactionCodeView()); } }; //Connect KO form to HTML return { init: function (elToBind) { var model = new ViewModel(); ko.applyBindings(model, elToBind); model.initialize(); } }; } ($); Here is our MVC model: namespace OurProject.Models.Input { public class InputModel : IModel { //Snip - lots of properties that aren't interesting for this problem [Required] [DisplayName("POS Transaction Codes")] public List<double> POSTransactionCodes { get; set; } public InputModel() { } /* I ommitted a few other methods that * aren't relevant to this problem. */ } }
I don't see how do you send the data back to the server but you need to name your inputs in way which allows model binding: If you're binding to a list/collection your inputs should be name like: <input type="text" name="CollectionPropertyName[index]" /> You can read about Model Binding To A List in this article So you just need generate proper names for your inputs: <input data-bind="value: code, attr: { name: 'POSTransactionCodes[' + $index() + ']' }" /> You should note that the above solution may only works if you're using the submit button and send the data form-urlencoded if you are sending the data as json you may need to tweak your serialization logic to make the model binder happy: In this case your json should something like this: { //... POSTransactionCodes: [ 1 , 3 ] //.. }
Thanks to nemesv's answer show me light on this one. But I need to have the "normal" name and id attribute for jquery validation. So I come up with the idea of writing my own data binder. ko.bindingHandlers.nameId = { update: function(element, valueAccessor, allBindingsAccessor, viewModel) { var value = valueAccessor(), allBindings = allBindingsAccessor(); var valueUnwrapped = ko.utils.unwrapObservable(value); var bindName = $(element).data('bind-name'); bindName = bindName.replace('{0}', valueUnwrapped); $(element).attr({name : bindName, id : bindName}); } }; And use it in html <input data-bind="value: qty, nameId: $index" data-bind-name="inventory[{0}].qty" /> jsfiddle
Sencha Touch Variable Missing error
In an effort to learn more about Sencha Touch I am building a calendar webapp for our university. I have some scripts that work but the problem is when I try to update the listPanel with the JSON data from Events.php. I am getting the data from the page but the update command is not updating the listPanel and instead for some reason that I can't put my finger on is asking for the events variable which is commented out. Now if I uncomment that variable it will parse the JSON in that variable but for the life of me i have no idea why. Here is the the index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Student Calendar</title> <link rel="stylesheet" href="css/ext-touch.css" type="text/css"/> <script type="text/javascript" src="js/ext-touch.js"></script> <script type="text/javascript" src="js/calendar.js"></script> <link rel="stylesheet" href="css/calendar.css" type="text/css"/> </head> <body> <textarea id="eventList" class="x-hidden-display"> <ul id="eventsItems"> <tpl for="."> <li class="date"> {date} <li> <tpl for="events"> <li>{title} - {location}</li> </tpl> </tpl> </ul> </textarea> <textarea id="eventList" class="x-hidden-display"> <ul id="eventsDescriptionList"> <tpl for="."> <li class="date"> {date} <li> <tpl for="events"> <li>{title} - {location}</li> </tpl> </ul> </textarea> <textarea id="eventDescription" class="x-hidden-display"> <tpl for="."> <p>{title}</p> <p>{description}</p> <p>{location}</p> <p>{startTime}</p> </tpl> </textarea> </body> </html> Here is the calendar.js Ext.setup({ onReady:function(){ eventListTemplate = Ext.XTemplate.from("eventList"); descriptionTemplate = Ext.XTemplate.from("eventDescription"); eventTapHandler = function(eventer,tapped){ tapID = tapped.id; /*Pass Into The Ajax Portion for getting a events description*/ Ext.Ajax.request({ params:{ /*params are available inside of the Ajax request*/ needs:eventDescription, panel:"descript", id:tapID, fails:rootPanel }, url: 'Events.php', method:'POST', success: function(response, opts) { /*Ext.uitl.JSON.decode() is used to change the response text to a JSON object*/ opts.params.needs.update(Ext.util.JSON.decode(response.responseText)); }, failure: function(response, opts) { alert("Sorry There Was An Error"); opts.params.fails.setCard(0); } }); rootPanel.setCard(1); } eventBackHandler = function(){ rootPanel.setCard(0); } backButton = { text:'Back', ui:'back', cls:'.backable', handler:eventBackHandler } toolBarBack = new Ext.Toolbar({ dock:'top', title:'Event Desciption', cls:'toolBar', items:[backButton], }); listPanel = new Ext.Panel({ tpl:eventListTemplate, scroll:'vertical', tester:function() { alert('MAGIC'); }, getEvent:function(){ var currentPanel = this; Ext.Ajax.request({ params:{ /*params are available inside of the Ajax request*/ panel:"list", needs:currentPanel, fails:rootPanel }, url: 'Events.php', method:'POST', success: function(response, opts) { var data = Ext.util.JSON.decode(response.responseText); //opts.params.needs.tester(); /*Ext.uitl.JSON.decode() is used to change the response text to a JSON object*/ opts.params.needs.update(data); }, failure: function(response, opts) { alert("Sorry There Was An Error"); } }); }, listeners: {el: {tap: eventTapHandler,delegate: '.touchable'}} }); eventDescription = new Ext.Panel({ tpl:descriptionTemplate, scroll:'vertical', dockedItems:[toolBarBack] }); rootPanel = new Ext.Panel({ fullscreen:true, layout:"card", animation: 'fade', items:[listPanel,eventDescription] }); //Offending Variable //var events = [{id:1,title:'this is a title',location:'here and now',startTime:'Right behind you'},{id:2,title:'this is a title2',location:'here and now2',startTime:'Right behind you2'}] //alert("done"); listPanel.getEvent(); } }); Here is the events.php Sql and database names have been changed to protect the innocent <? $dbname = "magicalDatabase"; require_once("../../../db_setup.inc"); If($_POST['panel'] == "list" ) { $currentMonth = date("m"); $currentYear = date("Y"); mysql_real_escape_string($currentMonth); mysql_real_escape_string($currentYear); $sql = "SELECT * FROM magicalcalendar WHERE calendar_start_year = '$currentYear' AND calendar_start_month = '$currentMonth' AND calendar_channel_guid = 'CurrentStudentsMain' ORDER BY calendar_start_month, calendar_start_day ASC"; $results = mysql_query($sql)or die(mysql_error()."------".__LINE__."-----$sql"); $dayCounts[01] = 31; $dayCounts[02] = 29; $dayCounts[03] = 31; $dayCounts[04] = 30; $dayCounts[05] = 31; $dayCounts[06] = 30; $dayCounts[07] = 31; $dayCounts[08] = 31; $dayCounts[09] = 30; $dayCounts[10] = 31; $dayCounts[11] = 30; $dayCounts[12] = 31; for($j=1;$j<$dayCounts[$currentMonth];$j++) { if($j<10) { $responce['0'.$j]['date'] = date(M)." - $j"; } else{ $responce[$j]['date'] = date(M)." - $j"; } } while($event = mysql_fetch_array($results)) { $responce[$event['calendar_start_day']]['events'][$event['calendar_id']]['id'] = $event['calendar_id']; $responce[$event['calendar_start_day']]['events'][$event['calendar_id']]['title'] = $event['calendar_subject']; $responce[$event['calendar_start_day']]['events'][$event['calendar_id']]['location'] = $event['calendar_location']; $responce[$event['calendar_start_day']]['events'][$event['calendar_id']]['startTime'] = $event['calendar_start_month']."-".$event['calendar_start_day']."-".$event['calendar_start_year']; } echo json_encode($responce); } If($_POST['panel'] == "descript") { $id = $_POST['id']; mysql_real_escape_string($id); $sql = "SELECT * FROM magicalcalendar WHERE calendar_id = $id"; $results = mysql_query($sql)or die(mysql_error()."------".__LINE__."-----$sql"); $i=0; while($event = mysql_fetch_array($results)) { $responce['id'] = $event['calendar_id']; $responce['description'] = $event['calendar_text']; $responce['title'] = $event['calendar_subject']; $responce['location'] = $event['calendar_location']; $responce['startTime'] = $event['calendar_start_day']."-". $event['calendar_start_month']."-".$event['calendar_start_year']; $i++; } echojson_encode($responce); } ?> Here is an example of the JSON data being sent { "05":{"events":{ "2856":{"id":"2856","title":"BSM Leadership Retreat","location":"Lake O' The Pines","startTime":"01-05-2011"}}}, "06":{"events":{ "2957":{"id":"2957","title":"Women's Basketball","location":"Brownwood, TX","startTime":"01-06-2011"}, "2958":{"id":"2958","title":"Men's Basketball","location":"Brownwood, TX","startTime":"01-06-2011"}}}, "08":{"events":{ "2959":{"id":"2959","title":"Women's Basketball","location":"Alpine, Tx","startTime":"01-08-2011"}, "2960":{"id":"2960","title":"Men's Basketball","location":"Alpine, TX","startTime":"01-08-2011"}}}, "11":{"events":{ "3052":{"id":"3052","title":"Theatre Auditions!","location":"Black Box Theatre","startTime":"01-11-2011"}}}, "12":{"events":{ "3054":{"id":"3054","title":"Welcome Back Party","location":"New Student Lounge","startTime":"01-12-2011"}}}, "13":{"events":{ "2961":{"id":"2961","title":"Women's Basketball","location":"Pineville, LA","startTime":"01-13-2011"}, "2962":{"id":"2962","title":"Men's Basketball","location":"Pineville, LA","startTime":"01-13-2011"}}}, "14":{"events":{ "3055":{"id":"3055","title":"Organizations Meeting","location":"Cornish Great room","startTime":"01-14-2011"}}}, "15":{"events":{ "2963":{"id":"2963","title":"Women's Basketball","location":"Clinton, MS","startTime":"01-15-2011"}, "2964":{"id":"2964","title":"Men's Basketball","location":"Clinton, MS","startTime":"01-15-2011"}}}, "20":{"events":{ "2965":{"id":"2965","title":"Women's Basketball","location":"ETBU\/Ornelas Gymnasium","startTime":"01-20-2011"}, "2966":{"id":"2966","title":"Men's Basketball","location":"Ornelas Gym\/ETBU","startTime":"01-20-2011"}}}, "21":{"events":{ "3056":{"id":"3056","title":"Karen Peck and New River","location":"Marshall Convention Center Auditorium","startTime":"01-21-2011"}, "3057":{"id":"3057","title":"Chamber Ensemble Recital","location":"Woods Great Room in OSC","startTime":"01-21-2011"}}}, "22":{"events":{ "2967":{"id":"2967","title":"Women's Basketball","location":"ETBU\/Ornelas Gymnasium","startTime":"01-22-2011"}, "2968":{"id":"2968","title":"Men's Basketball","location":"Ornelas Gym\/ETBU","startTime":"01-22-2011"}}}, "27":{"events":{ "2969":{"id":"2969","title":"Women's Basketball","location":"Clarksville, AR","startTime":"01-27-2011"}, "2970":{"id":"2970","title":"Men's Basketball","location":"Clarksville, AR","startTime":"01-27-2011"}, "3058":{"id":"3058","title":"CASL Conference","location":"Ornelas Student Center","startTime":"01-27-2011"}}}, "28":{"events":{ "2857":{"id":"2857","title":"ABIDE - A Reflective Prayer Conference","location":"TBD","startTime":"01-28-2011"}, "3059":{"id":"3059","title":"CASL Conference","location":"Ornelas Student Center","startTime":"01-28-2011"}, "3060":{"id":"3060","title":"ABIDE","location":"TBD","startTime":"01-28-2011"}}}, "29":{"events":{"2971":{"id":"2971","title":"Women's Basketball","location":"Richardson, TX","startTime":"01-29-2011"}, "2972":{"id":"2972","title":"Men's Basketball","location":"Richardson, TX","startTime":"01-29-2011"}, "3061":{"id":"3061","title":"CASL Conference","location":"Ornelas Student Center","startTime":"01-29-2011"}, "3062":{"id":"3062","title":"SAI Province Day","location":"JGMB and EDW","startTime":"01-29-2011"}}} } Also you can view the app here It's best viewed in safari either mobile or desktop.
A much more effective way to bind, say, a list to a JSON data source is to use a Ext.data.Proxy which will take care of all the AJAX and asynchronous updating of the list. I've taken the liberty of rewriting your app to demonstrate: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Scratch</title> <script src="lib/touch/sencha-touch-debug.js" type="text/javascript"></script> <link href="lib/touch/resources/css/sencha-touch.css" rel="stylesheet" type="text/css" /> <script> Ext.setup({ onReady:function(){ //DATA Ext.regModel('Event', { fields: [ {name:'id'}, {name:'title'}, {name:'location'}, {name:'startTime'} ], }); Ext.regStore('events', { model: 'Event', autoLoad: true, proxy: { type: 'ajax', url: 'events.json', reader: { type: 'json', root: 'events' } }, getGroupString: function(record) { return record.get('startTime'); } }); //UI eventListToolbar = new Ext.Toolbar({ title: 'Events' }); eventList = new Ext.List({ store: 'events', itemTpl: Ext.XTemplate.from("eventList"), listeners: { selectionchange: function (selectionModel, records) { if (records[0]) { eventDescription.update(records[0].data); eventDescriptionToolbar.setTitle(records[0].get('title')) rootPanel.setActiveItem(eventDescriptionPanel, {type:'slide'}); } } }, grouped:true }); eventListPanel = new Ext.Panel({ dockedItems: [eventListToolbar], items: [eventList] }); eventDescriptionToolbar = new Ext.Toolbar({ items: { text:'Back', ui: 'back', listeners: { tap: function () { rootPanel.setActiveItem(eventListPanel, {type:'slide', direction:'right'}); } } } }); eventDescription = new Ext.Panel({ tpl: Ext.XTemplate.from("eventDescription"), padding:20, }); eventDescriptionPanel = new Ext.Panel({ dockedItems: [eventDescriptionToolbar], items: [eventDescription], }); rootPanel = new Ext.Panel({ fullscreen:true, layout:"card", items:[ eventListPanel, eventDescriptionPanel ] }); } }); </script> </head> <body> <textarea id="eventList" class="x-hidden-display"> {title} - {location} </textarea> <textarea id="eventDescription" class="x-hidden-display"> <p>{title}</p> <p>{description}</p> <p>{location}</p> <p>{startTime}</p> </textarea> </body> </html> This consumes JSON that looks like this: {"events":[ {"id":"2856","title":"BSM Leadership Retreat","location":"Lake O' The Pines","startTime":"01-05-2011"}, {"id":"2957","title":"Women's Basketball","location":"Brownwood, TX","startTime":"01-06-2011"}, {"id":"2958","title":"Men's Basketball","location":"Brownwood, TX","startTime":"01-06-2011"}, {"id":"2959","title":"Women's Basketball","location":"Alpine, Tx","startTime":"01-08-2011"}, {"id":"2960","title":"Men's Basketball","location":"Alpine, TX","startTime":"01-08-2011"}, {"id":"3052","title":"Theatre Auditions!","location":"Black Box Theatre","startTime":"01-11-2011"}, {"id":"3054","title":"Welcome Back Party","location":"New Student Lounge","startTime":"01-12-2011"}, {"id":"2961","title":"Women's Basketball","location":"Pineville, LA","startTime":"01-13-2011"}, {"id":"2962","title":"Men's Basketball","location":"Pineville, LA","startTime":"01-13-2011"}, {"id":"3055","title":"Organizations Meeting","location":"Cornish Great room","startTime":"01-14-2011"}, {"id":"2963","title":"Women's Basketball","location":"Clinton, MS","startTime":"01-15-2011"}, {"id":"2964","title":"Men's Basketball","location":"Clinton, MS","startTime":"01-15-2011"}, {"id":"2965","title":"Women's Basketball","location":"ETBU\/Ornelas Gymnasium","startTime":"01-20-2011"}, {"id":"2966","title":"Men's Basketball","location":"Ornelas Gym\/ETBU","startTime":"01-20-2011"}, {"id":"3056","title":"Karen Peck and New River","location":"Marshall Convention Center Auditorium","startTime":"01-21-2011"}, {"id":"3057","title":"Chamber Ensemble Recital","location":"Woods Great Room in OSC","startTime":"01-21-2011"}, {"id":"2967","title":"Women's Basketball","location":"ETBU\/Ornelas Gymnasium","startTime":"01-22-2011"}, {"id":"2968","title":"Men's Basketball","location":"Ornelas Gym\/ETBU","startTime":"01-22-2011"}, {"id":"2969","title":"Women's Basketball","location":"Clarksville, AR","startTime":"01-27-2011"}, {"id":"2970","title":"Men's Basketball","location":"Clarksville, AR","startTime":"01-27-2011"}, {"id":"3058","title":"CASL Conference","location":"Ornelas Student Center","startTime":"01-27-2011"}, {"id":"2857","title":"ABIDE - A Reflective Prayer Conference","location":"TBD","startTime":"01-28-2011"}, {"id":"3059","title":"CASL Conference","location":"Ornelas Student Center","startTime":"01-28-2011"}, {"id":"3060","title":"ABIDE","location":"TBD","startTime":"01-28-2011"}, {"id":"2971","title":"Women's Basketball","location":"Richardson, TX","startTime":"01-29-2011"}, {"id":"2972","title":"Men's Basketball","location":"Richardson, TX","startTime":"01-29-2011"}, {"id":"3061","title":"CASL Conference","location":"Ornelas Student Center","startTime":"01-29-2011"}, {"id":"3062","title":"SAI Province Day","location":"JGMB and EDW","startTime":"01-29-2011"} ]} Slightly rough and ready. But it looks like: http://cl.ly/46dH & http://cl.ly/46Rl Not technically an answer to your question. But does that work?