Sencha Touch refresh list after data in store has been changed - ajax

i want to do the following:
I have a store which gets JSON data from the server. The JSON looks like this:
{"id":"1","name":"Name1","address":"exampleaddress1","lat":"48.366268","lng":"10.892320","distance":"0"},{...}]
My model and store:
Ext.regModel('Filiale', {
fields: ['id', 'name', 'address', 'distance', 'lat', 'lng'],
});
var ListStore = new Ext.data.Store({
model: 'Filiale',
id: 'ListStore',
autoLoad: false,
fields:['name', 'address', 'distance'],
proxy: {
type: 'ajax',
url : 'http://example.com/getSomeJson.php',
reader: {
type: 'json'
}
},
listeners: {
load: function(){
ListStore.each(function(store){
var newData = getDistance(store.data); // this function calculates the distance from currentLocation to the received address
console.log(newData); // i see a object in the console, with the correct calculated distance
console.log(newData.distance); // this shows the old distance which is set to '0' in the databse
//at this point i want to update the received records with the new distance, but the list always shows the old distance
});
}
}
});
I don't understand, why the two console.logs show different values for the distance. Can anyone explain that to me ?
My List:
var listPanel = new Ext.List({
title: 'ListStore',
store: ListStore,
id: 'addresslist',
itemTpl: '<div class="contact">{name}, {address}, {distance}</div>',
rendered: false,
listeners: {
beforerender: function(){
ListStore.load();
}
}
});
my function to calculate the distance:
var getDistance = function(dataset){
navigator.geolocation.getCurrentPosition(function(position){
var start = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
//add current position marker to map
var marker = new google.maps.Marker({
map: mapPanel.map,
position: start
});
var end = new google.maps.LatLng(dataset.lat, dataset.lng);
var service = new google.maps.DirectionsService();
var request = {
origin: start,
destination: end,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
service.route(request, function(result, status){
if (status == google.maps.DirectionsStatus.OK) {
dataset.distance = result.routes[0].legs[0].distance.value / 1000;
}
});
});
return dataset;
};
And as i said, the distance is correctly calculated and the objects gets returned... but i'm unable to update the records in the store or the list...

I don't understand, why the two console.logs show different values for the distance. Can anyone explain that to me ?
Are You using Chrome? Chrome console sometimes has problems with up-to-date console data
And as i said, the distance is correctly calculated and the objects gets returned... but i'm unable to update the records in the store or the list...
Records in the store in Your script are always up-to-date - in JS obejcts are passed by reference, so You don't even have to return newData - store object will be updated automatically
Just after adding some values to store type:
listpanel.refresh()
to load current store to list

Related

free-jqGrid 4.15.6 ExpandNode producing runtime error

I recently upgraded from the original Tony Tomov's jqGrid v4.5.4 to Oleg's free-jqGrid 4.15.6.
When using 4.5.4, the code below worked perfect, but in 4.15.6, it does not. The run-time error is produced by the two calls to expandNode and expandRow located in the forceNodeOpen() function. The error given:
TypeError: rc1 is undefined
The forceNodeOpen() function is used to force all ancestor nodes of the current treegrid node to show as expanded. Much like a table of contents...if we load an initial topic node, we want the whole topic hierarchy to be expanded:
// force a node (if expandable) to stay expanded
function forceNodeOpen(rowid)
{
var record = $("#tree").jqGrid('getRowData', rowid);
var div = $('tr#'+rowid).find('div.ui-icon.treeclick');
div.removeClass('ui-icon-triangle-1-e tree-plus').addClass('ui-icon-triangle-1-s tree-minus');
**$('#tree').jqGrid('expandNode', record);**
**$('#tree').jqGrid('expandRow', record);**
// get all ancestoral parents and expand them
// *NOTE*: the getAncestorNodes function of grid was not usable for
// some reason as the same code below just would not work
// with the return array from getAncestorNodes
var parent = $("#tree").jqGrid('getNodeParent', record);
while(parent)
{
forceNodeOpen(parent['id']);
parent = $("#tree").jqGrid('getNodeParent', parent);
}
}
// using topic url, get the tree row id
function getTopicID(topic)
{
var nodes = $('#tree').jqGrid('getRowData');
var rowid = 1;
$.each(nodes, function(e,i)
{
var url = $(this).attr('url');
if(url == topic)
{
rowid = $(this).attr('id');
return false;
}
});
return rowid;
}
// post request to help server via ajax
function loadTopic(topic)
{
// no need to load again
if(loadedtopic == topic) { return false; }
// select the topic node
var rowid = getTopicID(topic);
loading = true;
$('#tree').jqGrid('setSelection', rowid);
forceNodeOpen(rowid);
loading = false;
// wipe content
$('h1#help_content_topic span:first').html('Loading...');
$('div#help_content').html('');
// block UI for ajax posting
blockInterface();
// request help content
$.ajax(
{
type: 'POST',
url: '/index.php',
data: { 'isajax': 1, 'topic': topic },
success: function(data)
{
$.unblockUI();
$('h1#help_content_topic span:first').html(data['topic']);
$('div#help_content').html(data['content']);
return false;
}
});
// save current topic to prevent loading same topic again
loadedtopic = topic;
}
// table of contents
$('#tree').jqGrid({
url: "topics.php",
datatype: "xml",
autowidth: true,
caption: "Help Topics",
colNames: ["id","","url"],
colModel: [
{name: "id",width:1,hidden:true, key:true},
{name: "topic", width:150, resizable: false, sortable:false},
{name: "url",width:1,hidden:true}
],
ExpandColClick: true,
ExpandColumn: 'topic',
gridview: false,
height: 'auto',
hidegrid: false,
pager: false,
rowNum: 200,
treeGrid: true,
treeIcons: {leaf:'ui-icon-document-b'},
// auto-select topic node
gridComplete: function()
{
// save current topic to prevent loading same topic again
loadedtopic = '<? echo($topic) ?>';
var rowid = getTopicID('<? echo($topic) ?>');
$('#tree').jqGrid('setSelection', rowid);
forceNodeOpen(rowid);
$.unblockUI();
},
// clear initial loading
loadComplete: function()
{
loading = false;
},
onSelectRow: function(rowid)
{
// ignore initial page loads
if(loading) { return false; }
// load the selected topic
var topic = $("#tree").jqGrid('getCell',rowid,'url');
loadTopic(topic);
}
});
The forceNodeOpen(rowid) is invoked from the loadTopic() function, which is called inside the onSelectRow() event of the treegrid.
Not sure what 4.5.4 did that allowed this code to work but 4.15.6 finds it to be an error. The offending line in 4.15.6.src.js:
expandNode: function (rc) {
...
if (p.treedatatype !== "local" && !base.isNodeLoaded.call($($t), p.data[p._index[id]]) && !$t.grid.hDiv.loading) {
// set the value which will be used during processing of the server response
// in readInput
p.treeANode = rc1.rowIndex;
p.datatype = p.treedatatype;
...});
I have only included a few lines from the above core function. It's the p.treeANode = rc1.rowIndex that throws the error.
I have to be missing something but do not know what. Hoping somebody can tell me what to do. If I remark out the two expandNode and expandRow treegrid function calls in forceNodeOpen() function, the system does not error out and the desired topic loads. But the hierarchy is not expanded as desired.
START EDIT 1
The server-side code that returns the topic nodes:
echo("<?xml version='1.0' encoding='UTF-8'?>\n");
require('db.php');
echo("<rows>\n");
echo("<page>1</page>\n");
echo("<total>1</total>\n");
echo("<records>1</records>\n");
$sql = "SELECT node.id, node.parentid, node.topic, node.url, node.lft, node.rgt, (COUNT(node.parentid) - 1) AS depth
FROM helptopics AS node, helptopics AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.url ORDER BY node.lft";
$stmt = AMDB::selectStatement($sql);
while($data = $stmt->fetch(PDO::FETCH_ASSOC))
{
$id = $data['id'];
$pid = $data['parentid'];
$topic = $data['topic'];
$url = $data['url'];
$lft = $data['lft'];
$rgt = $data['rgt'];
$leaf = $rgt - $lft == 1 ? 'true' : 'false';
$exp = 'false';
$dep = $data['depth'];
echo("<row><cell>{$id}</cell><cell>{$topic}</cell><cell>{$url}</cell><cell>{$dep}</cell><cell>{$lft}</cell><cell>{$rgt}</cell><cell>{$leaf}</cell><cell>{$exp}</cell></row>\n");
}
echo("</rows>\n");
exit();
END EDIT 1
I see that you use
var record = $("#tree").jqGrid('getRowData', rowid);
to get node data of TreeGrid. It wasn't good, but it worked in old jqGrid because it saved internal jqGrid data twice: once as local data and once more time in hidden cells of the grid.
You should use getLocalRow instead of getRowData:
var record = $("#tree").jqGrid('getLocalRow', rowid);
The code will work on both old jqGrid and free jqGrid. Additionally, getLocalRow has always better performance comparing with getRowData even in jqGrid 4.5.4.

No such property: geometry when updating feature in openlayers 3 - Geoserver

I am working on a webmapping app with Openlayers 3, Postgresql and Geoserver 2.8, I want to make a WFS-T transactions for drawing and updating so I followed this steps https://medium.com/#goldrydigital/wfs-t-with-openlayers-3-16-6fb6a820ac58
Here is my modification code :
var dirty = {};
select.getFeatures().on('add', function(e) {
e.element.on('change', function(e) {
dirty[e.target.getId()] = true;
});
});
var clone;
select.getFeatures().on('remove', function(e) {
var f = e.element;
if (dirty[f.getId()]){
delete dirty[f.getId()];
featureProperties = f.getProperties();
delete featureProperties.boundedBy;
clone = new ol.Feature(featureProperties);
clone.setId(f.getId());
clone.setGeometryName("the_geom");
}
});
var node = formatwfs.writeTransaction(null, [clone], null, {
featureNS: "myNameSpace",
featureType: "myLayer"
});
$.ajax({
type: "POST",
url: "http://localhost:8080/geoserver/wfs",
data: new XMLSerializer().serializeToString(node),
contentType: 'text/xml',
success: function(data) {
alert((new XMLSerializer()).serializeToString(data));
},
error: function(e) {
var errorMsg = e? (e.status + ' ' + e.statusText) : "";
alert('Error saving this feature to GeoServer.<br><br>'
+ errorMsg);
},
context: this
});
the drawing part works fine but for the updating I get an error:
<ows:ExceptionText>No such property: geometry</ows:ExceptionText>
the geometry column in my table and layer is "the_geom" so I double check it on my code with setGeometryName("the_geom") but yet when I make the AJAX call I get the error above.
The first thing that came to my mind is to change the geometry column name in my postgresql table to geometry and republish the layer in geoserver, but I want to know first if there is any less obedient solution for this, thanks in advance
After changing the geometry column name in postgresql to "geometry" I get now another error :
<ows:ExceptionText>java.lang.NullPointerException</ows:ExceptionText>
I changed the geometry column name into "geometry" and after that the error relative to the Java null pointer came, then I found out that the XML code generated was wrong and needs to be modified for it refers to a wrong typeName feature:myLayer while it should be myNameSpace:myLayer for this one all I had to do was to replace it with Javascript :
var str=new XMLSerializer().serializeToString(node);
var data=str.replace("feature:myLayer","myNameSpace:myLayer");
In addition to Hicham Zouarhi's solution you can also change geometry type like this:
//Change feature name
const find_feature = `feature:${layerName}`;
const re_feature = new RegExp(find_feature, "g");
//Change feature geometry column
const find_geometry = `<Property><Name>geometry</Name>`;
const re_geometry = new RegExp(find_geometry, "g");
const payload = xs.serializeToString(formatWFS.writeTransaction(null, f, null, formatGML))
.replace(re_feature, `Bugra:${layerName}`)
.replace(re_geometry, `<Property><Name>${layerGeometryColumn}</Name>`);

Get values from selected CustomTile SAPUI5

I have a product catalog made with CustomTile Control. When I press one tile, I want to go to a details page. For that I need to know some of the values that are on the pressed tile, which I'm not able to.
Here is the code for the tile and the binding:
var sServiceUrl = "/sap/opu/odata/sap/ztestefardas_srv/"; //URL do serviço oDATA
var oModel = new sap.ui.model.odata.ODataModel(sServiceUrl);
sap.ui.getCore().setModel(oModel);
OData.read("/sap/opu/odata/sap/ztestefardas_srv/catalogo",
function (response){
for(var key in response.results) {
var value = response.results[key];
var oImg =new sap.ui.commons.Image({
width :"160px",
height :"160px"
}).setSrc(value["img"]);
oImg.addStyleClass("img_cat");
var oMatxt =new sap.ui.commons.TextView({
text: value["matxt"],
width: "200px"
}).addStyleClass("matxt");
var oAtr =new sap.ui.commons.TextView({
text: "Atribuídos: "+value["n_atr"],
width: "200px"
}).addStyleClass("second_line");
if (value["n_dis"] > 0){
var oDis =new sap.ui.commons.TextView({
text: "Disponíveis: "+value["n_dis"],
width: "200px"
}).addStyleClass("second_line_disp");
} else {
var oDis =new sap.ui.commons.TextView({
text: "Disponíveis: "+value["n_dis"],
width: "200px"
}).addStyleClass("second_line");
}
var oPtxt =new sap.ui.commons.TextView({
text: "Próximo levantamento:",
width: "200px"
}).addStyleClass("third_line");
var oPlev =new sap.ui.commons.TextView({
text: value["p_lev"],
width: "200px"
}).addStyleClass("third_line");
var oLayout = new sap.ui.commons.layout.VerticalLayout({
content: [oImg,oMatxt,oAtr,oDis,oPtxt,oPlev]
});
var oTile = new sap.m.CustomTile({
content:oLayout,
press: function(oEvento){
//missing code to get values from selected tile
oNavContainer.to(Page2);
}
}).addStyleClass('sapMTile');
oContainer.addTile(oTile);
}});
I've tried with the table attach row selection change way, but it's not working too.
Can you please help?
Thank you.
Add the following code in your function (response) method:
var valueModel = new sap.ui.model.json.JSONModel({
"Value": "##your value here##",
});
oLayout.setModel(valueModel);
Add the following code in the press function handler:
var oLayout = oEvento.getSource().getContent();
var value = oLayout .getModel().getProperty("/Value");
Then you can get values from the CustomTile by using data binding to get the value your want.
Hope it helps.
I found a way to make this work.
within the FOR that I used to read the data from the odata:
oTile.data("matnr", value["Matnr"]);
oTile.data("matxt", value["Itmfdx"]);
oTile.data("n_dis", value["n_dis"]);
oTile.data("n_atr", value["n_atr"]);
oTile.data("endda", value["Endda"]);
oTile.data("itmfd", value["Itmfd"]);
these value["xpto"] are the keys from the response results (OData.read("/sap/opu/odata/sap/zmm_fardamentos_srv/CatalogoSet?sap-ui-language=PT",
function (response){
for(var key in response.results) {
var value = response.results[key];)
Then, I created a function for the attachPress event of oTile with these:
oTile.attachPress( function(){
sap.ui.getCore().getControl("selimg").setSrc(this.data("img"));
sap.ui.getCore().getControl("bigpic").setSrc(this.data("img"));
sap.ui.getCore().getControl("nome_material").setText(this.data("matxt"));
sap.ui.getCore().getControl("itmfd_var").setText(this.data("itmfd"));
sap.ui.getCore().getControl("atr_det").setText(this.data("n_atr"));
sap.ui.getCore().getControl("disp_det").setText(this.data("n_dis"));
sap.ui.getCore().getControl("lev_data").setText(this.data("endda"));
the names within getControl are the id of the variables that will hold the values.
Maybe this is not the fanciest way, but it sure works :)

Dirtychange change event in a formpanel

I have a formpanel, which displays information after clicking on a company in my grid.
this is the handler for my clickevent on the grid:
var onCompanyGridClickHandler = function (grid, rec) {
Ext.Ajax.request({
url: '../GetCompany',
params: { id: rec.get('id') },
success: function (res) {
//Fill Fields with values
companyFormValues = JSON.parse(res.responseText);
companyInfoFormPanel.getForm().setValues(companyFormValues);
}
});
};
So everytime I click on the grid, the form gets new values.
How can I implement a dirty change listener, which reminds me, when I changed a form value, to save the changes.
I tried to fire the isdirty on a beforeclick event on the grid, but it didn't work, and all I get is a dirtychange on every form that changes.
This should work.
var onCompanyGridClickHandler = function (grid, rec) {
form = companyInfoFormPanel.getForm();
if(!form.isDirty()){
Ext.Ajax.request({
url: '../GetCompany',
params: { id: rec.get('id') },
success: function (res) {
//Fill Fields with values
companyFormValues = JSON.parse(res.responseText);
companyInfoFormPanel.getForm().setValues(companyFormValues);
}
});
}
else{
Ext.Msg.alert("Warning", "Please save the data!!")
}
};
Simple Working fiddle for reference.
Was missing trackResetOnLoad:true
Updated Fiddle : Updated

JQPlot: Plot series and labels from an external source

I am working with JQPlot to generate a chart pulling data from a database, like in the example here http://www.jqplot.com/tests/data-renderers.php.
The chart is working fine, but at the moment the series labels are hard coded. How can I make this chart to display the series labels from the database too, just like the series? I assume I need to make a new call, to a second file containing the label names, but I am not really sure how to do that. Any ideas?
Here is the code I am using:
$(document).ready(function(){
var ajaxDataRenderer = function(url, plot) {
var ret = null;
$.ajax({
async: false,
url: url,
dataType:'json',
success: function(data) {
ret = data;
}
});
return ret;
};
var jsonurl = "./index.php";
$.jqplot.config.enablePlugins = true;
plot1 = $.jqplot('chart1', jsonurl,{
dataRenderer: ajaxDataRenderer,
title: 'Annual Balance Summary',
legend: {show:true, renderer:$.jqplot.EnhancedLegendRenderer},
seriesDefaults: {lineWidth:4},
**series:[{label:'Tilikausi 01/2009 - 12/2009'}, {label:'Tilikausi 01/2010 - 12/2010'}, {label:'Tilikausi 01/2011 - 12/2011'}]**, // THIS ARE THE VALUES I WANT TO BRING FROM THE DATABASE
showMarker:true,
pointLabels: { show:true },
axes: {
xaxis: {pad:1, numberTicks:12, tickInterval: 1, autoscale:true, tickOptions:{formatString:'%d', fontSize:'10pt', fontFamily:'Tahoma', angle:-40, fontWeight:'normal'}}},
highlighter: {bringSeriesToFront: true}
});
});
The outcoming json array of the index.php, look like this:
[[[0,413010.71],[1,431586.96],[2,418659.56],[3,418776.76],[4,409203.91],[5,392167.56],[6,547296.04],[7,529292.86],[8,523009.35],[9,541452.97],[10,535397.58],[11,555497.48],[12,465849.17]],[[0,465849.17],[1,464569.69],[2,468339.1],[3,471005.39],[4,470786.79],[5,472315.46],[6,492847.16],[7,495973.32],[8,520188.21],[9,550497.27],[10,544294.18],[11,559081.4],[12,479558.69]],[[0,479558.69],[1,467694.94],[2,459592.48],[3,476012.25],[4,463623.8],[5,487588.68],[6,445992.44],[7,457935.72],[8,481076.75],[9,498464.53],[10,508681.42],[11,523928.66],[12,548180.15]]]
The array for the series labels should be something like this:
[["Tilikausi 01\/2009 - 12\/2009"],["Tilikausi 01\/2010 - 12\/2010"],["Tilikausi 01\/2011 - 12\/2011"]] // Array of series labels
Thanks in advance for your answers!
I think the key to this one is getting the JSON structured correctly that is retrieved by index.php.
Currently you are returning this:
[[[0,413010.71],[1,431586.96],[2,418659.56],[3,418776.76],[4,409203.91],[5,392167.56],[6,547296.04],[7,529292.86],[8,523009.35],[9,541452.97],[10,535397.58],[11,555497.48],[12,465849.17]],[[0,465849.17],[1,464569.69],[2,468339.1],[3,471005.39],[4,470786.79],[5,472315.46],[6,492847.16],[7,495973.32],[8,520188.21],[9,550497.27],[10,544294.18],[11,559081.4],[12,479558.69]],[[0,479558.69],[1,467694.94],[2,459592.48],[3,476012.25],[4,463623.8],[5,487588.68],[6,445992.44],[7,457935.72],[8,481076.75],[9,498464.53],[10,508681.42],[11,523928.66],[12,548180.15]]]
But what you really need is something like this (some elements of values omitted for brevity):
{
values: [[[0,413010.71],[1,431586.96],[2,418659.56],[3,418776.76], ... [12,548180.15]]],
labels: [["Tilikausi2 01\/2009 - 12\/2009"],["Tilikausi2 01\/2010 - 12\/2010"],["Tilikausi2 01\/2011 - 12\/2011"]]
}
The tricky thing is that labels are assigned to a series when the graph is created. This causes a problem because it really means that the Ajax call must happen prior to creating the graph.
Given the Json as structured above, something like this should do the trick:
$.jqplot.config.enablePlugins = true;
var jsonurl = "./index.php";
//Get the data prior to creating the graph.
var plotData = ajaxDataRenderer(jsonurl);
//plotData.values is now passed in to be the actual data the plot is created from.
plot1 = $.jqplot('chart1', plotData.values, {
title: 'Annual Balance Summary',
legend: {show:true, renderer:$.jqplot.EnhancedLegendRenderer},
seriesDefaults: {lineWidth:4},
//The series labels can now be supplied.
series: plotData.labels,
showMarker:true,
pointLabels: { show:true },
axes: {
xaxis: {pad:1, numberTicks:12, tickInterval: 1, autoscale:true, tickOptions:{formatString:'%d', fontSize:'10pt', fontFamily:'Tahoma', angle:-40, fontWeight:'normal'}}},
highlighter: {bringSeriesToFront: true}
});
Edit:
The other thing you will need to do is modify the labels array that comes back. We are still using the ajaxDataRenderer function, so just after you have received the data you will need to do this:
for(var i = 0; i < data.labels.length; i++) {
data.labels[i] = { label: data.labels[i][0] };
}
All this does is create the kind of object literal that jqplot is expecting when you are specifying labels.
Edit 2:
If your JSON looks like:
[[["Tilikausi 01\/2009 - 12\/2009"],["Tilikausi 01\/2010 - 12\/2010"],
["Tilikausi 01\/2011 - 12\/2011"]],[[[1,-4308.6],[2,-11725.18],[3,-23253.57],
...,[10,-85437.15],[11,-10‌​5465.7],[12,-129859.38]]]]
Then it should still work, but you would need to refer to things differently. Instead of plotData.values you would have plotData[1], and instead of plotData.labels you would have plotData[0].
Also, the label rearrangement code would instead look like:
for(var i = 0; i < data[0].length; i++) {
data[0][i] = { label: data[0][i][0] };
}
Read your values in a javascript array and use it to display values in the legend using the following code-snippet:
legend:{
show: true,
location: 'ne',
placement: "outside",
labels: companies
}

Resources