EXTJS 4: Editable grid doesn't commit changes to MySQL Database - php

Dear fellow EXT enthusiasts,
I'm working on a project where I need an admin panel to edit job functions.
The grid is communicating to a MySQL database using Ext.Direct. It loads the data fine.
The grid shows the id and the function name
I added a RowEditing plugin to my grid for editting the function settings.
The problem is, when I try to commit the changes I get a tiny red triangle in the upper left corner of the grid without any error code in the console. The changes don't commit to the MySQL database.
The way my program works and loads the data:
This is my functionStore:
Ext.direct.Manager.addProvider(Ext.app.REMOTING_API);
Ext.define("MCS.store.FunctionStore",
{
extend: "Ext.data.Store",
requires: "MCS.model.Functions",
model: "MCS.model.Functions",
id: "FunctionStore",
proxy:
{
type: "direct",
api:
{
read: QueryDatabase.getFunctions,
create: QueryDatabase.createFunction,
update: QueryDatabase.updateFunction,
destroy: QueryDatabase.removeFunction,
}
},
});
In the controller: when the admin panel is rendered, the store gets loaded with the following function:
loadStore: function()
{
functionStore.load();
}
This is the grid where the functions are displayed:
var rowEditingFunctions = Ext.create("Ext.grid.plugin.RowEditing",
{
clicksToMoveEditor: 1,
autoCancel: false,
listeners: {
edit: function(editor,e,opt)
{
var grid = e.grid;
var record = e.record;
console.log(record.data.functionName);
var editedrecords = grid.getStore().getUpdatedRecords();
console.log(editedrecords);
}
}
});
var functionGrid = Ext.create("Ext.grid.Panel",
{
height: 500,
width: 800,
store: functionStore,
title:"List of Job Functions - double click to edit",
columns: [
{
dataIndex: "id",
width: 50,
text: "ID"
},{
dataIndex: "functionName",
flex: 1,
text: "Function",
field:
{
type: "textfield",
allowBlank: false
}
}],
plugins: [
rowEditingFunctions
],
dockedItems: [
{
xtype: "toolbar",
store: functionStore,
dock: "bottom",
items: [
{
iconCls: "add",
text: "Add",
handler: function()
{
rowEditingFunctions.cancelEdit();
var newRecord = Ext.create("App.model.Functions");
functionStore.insert(0, newRecord);
rowEditingFunctions.startEdit(0, 0);
var sm = functionGrid.getSelectionModel();
functionGrid.on("edit", function() {
var record = sm.getSelection()
functionStore.sync();
functionStore.remove(record);
functionStore.load();
});
}
}, {
iconCls: "delete",
text: "Delete",
handler: function()
{
rowEditingFunctions.cancelEdit();
var sm = functionGrid.getSelectionModel();
Ext.Msg.show(
{
title:"Delete Record?",
msg: "You are deleting a function permanently, this cannot be undone. Proceed?",
buttons: Ext.Msg.YESNO,
icon: Ext.Msg.QUESTION,
fn: function(btn)
{
if(btn === "yes")
{
functionStore.remove(sm.getSelection());
functionStore.sync();
}
}
});
}
}]
}]
});
As u can see I added a listener to the edit event of the RowEditing plugin, this displays the array of the edited record in console like it should.
4. And finally, this is the PHP code that updates the database:
public function updateFunction(stdClass $params)
{
$db = $this->__construct();
if ($stmt = $db->prepare("UPDATE functions SET functionName=? WHERE id=?"))
{
$stmt->bind_param('si', $functionName, $id);
$functionName = $params->functionName;
$id = (int) $params->id;
$stmt->execute();
$stmt->close();
}
return $this;
}
5. The weird part: once I've added one job function, I can edit all the other functions and those changes are committed to the database...
As a side note: I'm just a beginner in EXT, trying to learn it on my own, but I have been breaking my head on this issue for the last few days so I decided to ask you guys.
Thanks for your answers in advance!

I left the bug for what it was for a few weeks and started to look into it again this week.
I found a work around solution.
I've added the following code to my controller that controls the grids:
functionGrid.on('edit', function(editor, e)
{
e.store.sync();
});
Now when I update a record, the tiny red triangle still appears but after the e.store.sync() function is completed it disappears and the database table is updated.
Not a 100% clean solution, but it does the trick
If anyone has a better solution, please let me know

Related

How to populate Jvector Map with countries from database?

(I am new to Javascript and jQuery..) I have a dashboard and I want to display a map that shows the countries where participants of a particular event are coming from. With this, I opted with Jvector Map. I am having a hard time displaying the countries in the map, coming from my database.
dashboard.js
var mapData = {};
$('#world-map').vectorMap({
map: 'world_mill_en',
backgroundColor: "transparent",
regionStyle: {
initial: {
fill: '#e4e4e4',
"fill-opacity": 0.9,
stroke: 'none',
"stroke-width": 0,
"stroke-opacity": 0
}
},
series: {
regions: [{
values: function() {
$.ajax({
url:"includes/sql/fetchcountries.php",
method:"GET",
data:mapData,
dataType:"json",
success: function(data){
mapData = data;
console.log(mapData);
}
})
},
scale: ["#1ab394", "#22d6b1"],
normalizeFunction: 'polynomial'
}]
},
});
fetch.php
<?php
require '../auth/dbh.inc.auth.php';
$id = $_SESSION['ntc_id'];
$stmt = $conn->prepare("SELECT DISTINCT(participants.p_country) FROM ntc_participants
INNER JOIN participants ON participants.p_id=ntc_participants.p_id_fk
WHERE ntc_participants.ntc_id_fk=?");
$data = array();
mysqli_stmt_bind_param($stmt, "i", $id);
$stmt->execute();
$result = $stmt->get_result();
if($result->num_rows === 0);
if($row = $result->fetch_assoc()) {
$data[] = [
$row['p_country'] => 0 ]; //the value 0 is just a placeholder.. The jvector map feeds on this format: "US":298, "SA": 200
}
echo json_encode($data);
?>
Could anyone be gracious enough to walk me through all the wrong things I'm doing in my code? Appreciate all the help! :)
Ajax is asynchronous, so You are creating the map before the data has been downloaded.
Initialize the map with empty values for Your region:
$('#world-map').vectorMap({
...
values: {}
...
});
Then, whenever You need to show the data, set it dynamically:
$.get("includes/sql/fetchcountries.php", function(data) {
var mapObj = $("#world-map").vectorMap("get", "mapObject");
mapObj.series.regions[0].setValues(data);
});
During the ajax invocation and data download maybe You can show a spinner (please look at beforeSend inside the jQuery full ajax documentation: https://api.jquery.com/jquery.ajax/).
Here is the reference for setValues:
http://jvectormap.com/documentation/javascript-api/jvm-dataseries/
http://api.worldbank.org/v2/country/all/indicator/NY.GDP.PCAP.PP.CD?format=json&date=2018
This link will give you up-to-date stats for most common indicators via json - and then you can pluck whatever data that you like. I don't have all the code yet, as I am working on this today too.
This answers the question above whenever your database can also present JSON
document.addEventListener('DOMContentLoaded', () => {
console.log("loaded")
fetchCountryData()
})
function fetchCountryData () {
fetch('http://api.worldbank.org/v2/country/all/indicator/NY.GDP.PCAP.PP.CD?format=json&date=2018')
//
.then(resp => resp.json())
.then(data => {
let country.id = data[1]
let indicator.id = data[1]
create-GDP-Data(country.id,indicator.id)
})
}
function create-GDP-Data(country.id,indicator.id){
let gdpData = ?
}
$('#world-map-gdp').vectorMap({
map: 'world_mill',
series: {
regions: [{
values: gdpData,
scale: ['#C8EEFF', '#0071A4'],
normalizeFunction: 'polynomial'
}]
},
onRegionTipShow: function(e, el, code){
el.html(el.html()+' (GDP - '+gdpData[code]+')');
}
});

multiple ajax requests from one page + how to do + best practice

I am working on google charts at the minute and I have got a basic one setup.
What it does at present is connects to a DB and returns a dataset based on 1 query. I am wondering is, if I want to draw more charts with different queries to the database how do I do this? Or what is the best practice?
For instance, there is already one connection with one query, how can I add another query, and then draw the charts based on what is returned?
I understand that might be a broad question, but maybe someone could show me how I would return a different query/dataset from the DB?
This is my code:
$(document).ready(function(){
console.log("hello world")
//alert("result")
$.ajax({
url:"data.php",
dataType : "json",
success : function(result) {
google.charts.load('current', {
'packages':['corechart','bar']
});
google.charts.setOnLoadCallback(function() {
console.log(result[0]["name"])
drawChart(result);
});
}
});
//add a 2nd call - will need a 2nd draw charts to draw the different dataset assuming it will be different
// - will need a 2nd data.php as the query will be different on the dataset
$.ajax({
url:"data.php",
dataType : "json",
success : function(result2) {
google.charts.load('current', {
'packages':['corechart','bar']
});
google.charts.setOnLoadCallback(function() {
console.log(result2[0]["name"])
drawChart(result2);
});
}
});
function drawChart(result) {
var data = new google.visualization.DataTable();
data.addColumn('string','Name');
data.addColumn('number','Quantity');
var dataArray=[];
$.each(result, function(i, obj) {
dataArray.push([ obj.name, parseInt(obj.quantity) ]);
});
data.addRows(dataArray);
var piechart_options = {
title : 'Pie Chart: How Much Products Sold By Last Night',
width : 400,
height : 300
}
var piechart = new google.visualization.PieChart(document
.getElementById('piechart_div'));
piechart.draw(data, piechart_options)
var columnchart_options = {
title : 'Bar Chart: How Much Products Sold By Last Night',
width : 400,
height : 300,
legend : 'none'
}
//var barchart = new google.visualization.BarChart(document
// .getElementById('barchart_div'));
//barchart.draw(data, barchart_options)
var chart = new google.charts.Bar(document.getElementById('columnchart_material'));
chart.draw(data, google.charts.Bar.convertOptions(columnchart_options));
} //have added this column chart but need to wrok out if it is best practice????
});
I am getting an object back from my DB query, but I want to know how to return more/different datasets from the same DB connection? For example what if I wanted to draw another chart with the dataset returned from this query select * from product where name="Product1" OR name="Product2";
0: Object { id: "1", name: "Product1", quantity: "2" }
​1: Object { id: "2", name: "Product2", quantity: "3" }
​2: Object { id: "3", name: "Product3", quantity: "4" }
​3: Object { id: "4", name: "Product4", quantity: "2" }
​4: Object { id: "5", name: "Product5", quantity: "6" }
​5: Object { id: "6", name: "Product6", quantity: "11" }
For what it is worth my php code is as follows:
data.php
<?php
require_once 'database.php';
$stmt = $conn->prepare('select * from product');
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_OBJ);
echo json_encode($results);
?>
database.php
<?php
$conn = new PDO('mysql:host=192.168.99.100;dbname=demo','root', 'root');
?>
note: this might be of interest
google charts only needs to be loaded once per page load,
not every time you need to draw a chart
also, google.charts.load can be used in place of --> $(document).ready
it will wait for the page to load before executing the callback / promise
recommend setup similar to following snippet...
google.charts.load('current', {
packages: ['corechart', 'bar']
}).then(function () {
$.ajax({
url: 'data.php',
dataType: 'json'
}).done(drawChart1);
$.ajax({
url: 'data.php',
dataType: 'json'
}).done(drawChart2);
});
function drawChart1(result) {
...
}
function drawChart2(result) {
...
}

Kendo subgrid deletion (with php)

I use example like this:Tutorial for Kendo and PHP
And I use code in subgrid as in grid:
subDS = new kendo.data.DataSource({
transport: {
read: "data/channelName.php?acc="+e.data.userId,
destroy: {
url: "data/chMove.php",
type: "DELETE",
complete: function (e) {
$("#grid").data("kendoGrid").dataSource.read();
}
}
},
error: function(e) {
alert(e.responseText);
},
schema: {
data: "results",
model: {
id: "channelId"
}
}
});
detailRow.find(".subgrid").kendoGrid({
dataSource: subDS,
columns: [
{
title: "Channel Name", field: "channelname"
},
{
command: ["destroy"], title: " ", width: "100px"
}]
});
However, the code isn't fired in server side of PHP code,
I not sure it is client side code wrong or server side?
The read is return:
{"results":[{"channelname":"test"},{"channelname":"5413trret"},{"channelname":"d453"},{"channelname":"test3"},{"channelname":"ter"},{"channelname":"test5"}]}
and userId is in the read of the grid.
The server side(chMove.php) I try to test if it is fired use alert like:
<?php
// determine the request type
$verb = $_SERVER["REQUEST_METHOD"];
echo "<script>alert('"."123"."');</script>";
?>
But the alert never be fired, needless to say I want to get the parse_str(file_get_contents('php://input'), $request );
later and parse the $request.
The final goal is delete what user click in the "Delete" button and the server side can delete it in database.
Any idea about my code?
Or is there any other method to do deletion of subgrid?
Any advice appreciate.
OK, I have alternate method.
I look the manual : Below show how to fired remove function
And the code is like:
var detailRow = e.detailRow;
subDS = new kendo.data.DataSource({
transport: {
read: "data/channelName.php?acc="+e.data.userId
},
error: function(e) {
alert(e.responseText);
},
schema: {
data: "results",
model: {
id: "channelid",
fields: {
channelname:{ editable: false}
}
}
}
});
// create a subgrid for the current detail row, getting territory data for this employee
detailRow.find(".subgrid").kendoGrid({
columns: [
{ title: "Channel Name", field: "channelname"},
{ command: "destroy", title: " ", width: "100px" }
],
dataSource: subDS,
editable: true,
remove: function(e) {
//alert("Removing:" + e.model.channelid);
var xmlhttp2;
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp2=new XMLHttpRequest();
} else {
xmlhttp2=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp2.open("POST","data/chMove.php",true);
xmlhttp2.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp2.send("channel="+e.model.channelid);
}
});
The most important is set your subgrid to be editable( I don't set the attribute before),
and the model of id can let you use in your data("results").
And I also show my trick to connect to PHP side :)
Then you can handle the server side as usual:
(in chMove.php)
$channel=mysql_real_escape_string($_POST["channel"]);
It takes me a lot of time to deal with it, I hope it is helpful.

Called PHP script using EXTJS alert message box

I am currently trying to call the PHP script upon clicking OK button on EXTJS message alert box.
For some reason it doesn't even display the Alert box when I use handler. However when I used Listener it displays the Alert box but doesn't call the php script upon clicking OK button. I read on different blogs and come to know Handler is the best way to go forward
I will appreciate if somebody can help me or point me to the right direction. I am using the latest release of EXTJS4
Below is the EXTJS tree panel code I've written using handler;
var treePanel = Ext.create('Ext.tree.Panel', {
id: 'tree-panel',
title: 'Available Database',
region: 'north',
split: true,
height: 360,
minSize: 150,
rootVisible: false,
autoScroll: true,
store: store,
handler: function() {
if (treePanel.getSelectionModel().hasSelection()) {
var selValue = treePanel.getSelectionModel().getSelection();
Ext.MessageBox.alert('Press OK to confirm your subscription <br>' + selValue[0].data.text,
function(btn, text) {
if (btn == 'ok') {
Ext.Ajax.request({
url: 'addSubscription.php',
params: {
nodetext: text,
parentid: selectedNode[0].data.id
},
success: function(response) {
var id = response.responseText;
grid.getView().refresh();
}
})
} else {
Ext.MessageBox.alert('Record already subscribed');
}
});
}
}
});
Ext.tree.Panel have not 'handler' property in config.
Handler is a function that is executed when you click on some of the components - such as buttons.
You can add button on your treePanel toolbar, and use button handler:
...
tbar: [{
xtype: 'button',
text: 'Subscribe',
handler: function(button) {
...
}
}],
...
See on jsfiddle: http://jsfiddle.net/FFvLa/
but doesn't call the php script upon clicking OK button.
The function must be passed as the third argument in Ext.Msg.alert:
http://jsfiddle.net/FFvLa/2/

How to render different view on selecting tabs in ext js4?

1)I have a json file which I want to display in view.
{
"contents": [
{
"title":'JWorld',
"image":'image/e-learning/elearning.png',
"subtitle":[
{
"categories":'Aus',
},
{
"categories":'England',
}
]
},
{
"title":'JIndia',
"image":'image/Content/History_of_India.jpg',
"subtitle":[
{
"categories":'History',
},
{
"categories":'India palace',
}
]
},
{
"title":'JMaharastra',
"image":'image/Content/Geography.jpg',
"subtitle":[
{
"categories":'History Maharastra',
},
{
"categories":'Maharastra Heros',
}
]
}
]
}
2)My view file :--
Ext.define('Balaee.view.kp.dnycontentcategories.ContentcategoriesView',
{
extend:'Ext.view.View',
id:'contentcategoriesViewId',
alias:'widget.ContentcategoriesView',
store:'kp.DnycontentcategoriesStore',
config:
{
tpl:'<tpl for="0">'+
'<div class="main">'+
'</br>'+
'<b>{title}</b></br>'+
'<img src={image} hight="50" width="100"></br>'+
'</div>'+
'</tpl>',
itemSelector:'div.main',
}
});// End of class
3) i am using tab panel and dynamically adding tabs in it using json file.
Ext.define('Balaee.view.kp.dnycontentcategories.Contentcategories',{
extend:'Ext.tab.Panel',
requires:[
'Balaee.view.kp.dnycontentcategories.ContentcategoriesView','Balaee.view.kp.dnycontentcategories.ContentcategoriesView1'
],
id:'contentcategoriesId',
alias:'widget.Contentcategories',
height:500,
items:[
],//end of items square
});// End of login class
4) My store file:--
Ext.define('Balaee.store.kp.DnycontentcategoriesStore',{
extend: 'Ext.data.Store',
model: 'Balaee.model.kp.DnycontentcategoriesModel',
autoLoad:true,
// filters: [{
// property: 'title',
// }],
proxy:
{
type:'ajax',
api:
{
read:'data/content.json',
//create: ,
//update: ,
//destroy: ,
},//End of api
reader:
{
type:'json',
root:'contents',
//successProperty: ,
}//End of reader
}//End of proxy
});//End
5) My Controller file some code
here I am dynamically adding some tabs from json file.And selecting particular tab I want different particular values from json file. But I get same view of first tab. How can I solve this problem.
init: function(){
console.log("inside content controller");
this.control({
'Contentcategories':
{
render:this.renderFunction,
}
});//End of control
},//End of init() function
renderFunction:function(){
console.log("Inside render function");
var tabPanel = Ext.getCmp('contentcategoriesId'); // tabpanel
var tabPanelView = Ext.getCmp('contentcategoriesViewId'); // tabpanel view
var storeObject= this.getStore('kp.DnycontentcategoriesStore'); // store
storeObject.on('load',function(){
storeObject.each(function(model){
//tabPanelView.store().filter('title',model.get('title')),
console.log(model.get('title'));
console.log(model.get('categories'));
tabPanel.add({title:model.get('title'),
id:model.get('title'),
//html:"<image src=model.get('image')>",
xtype:'ContentcategoriesView',
}); //End of add function
});// End of storeObject function
tabPanel.setActiveTab(0);
});
},// End of render function
please give me some suggestion.
There are a few issues with your code.
You define ContentcategoriesView - its a a component you have extended; but you give it an id (contentcategoriesId) yet you are creating more than one of these components - it makes no sense as an id has to be unique per component instance.
Then, you attach a store to this view, which means all components will render the same.
If I understand correctly you want each entry in your json to become a different tab.
I would take this direction (code not tested, but should give you a direction):
Ext.define('Balaee.view.kp.dnycontentcategories.ContentcategoriesView',
{
extend:'Ext.panel.Panel', // Notice it's a panel.
alias:'widget.ContentcategoriesView',
config:
{
tpl: '<div class="main">' +
'</br>' +
'<b>{title}</b></br>' +
'<img src={image} hight="50" width="100"></br>' +
'</div>'
itemSelector:'div.main',
}
});
And then:
storeObject.on( 'load',function() {
storeObject.each( function( model ) {
tabPanel.add({
xtype: 'ContentcategoriesView',
title: model.get( 'title' ),
id: model.get( 'title' ),
data: model
});
});
tabPanel.setActiveTab(0);
});

Categories