Selectize.js get more data in "onItemAdd" callback - javascript

TL;DR
To make it clearer, I want to have access to ALL the data in the selected JSON object inside the onItemAdd function. Right now I only have access to _id and name via the config variables.
Ok, so I have a working Selectize.js function grabbing a JSON object from my server and creating the select options.
What I want to know is, can I get anymore data from the existing JSON object inside the "onItemSelect" callback?
The only data I can get directly is the value as specified in the config, which in this case is the "_id" and the $item which i assume is form the labelField in the config, in this case is the name form the JSON data.
How can I get more data than that for the selected item? You see in the render object I use the variable item.sku, how can I access the sku variable in the "onItemAdd" callback?
the data form the server is a json array:
[
{ _id: 'abcd1234', name: 'Sample', sku: '00123' },
{ _id: 'efgh5678', name: 'Sample2', sku: '00124' }
]
My function
// setup select box to add new products to list
$('#buyingGroupAddProducts').selectize({
valueField: '_id',
labelField: 'name',
searchField: 'name',
options: [],
create: false,
closeAfterSelect: true,
render: {
option: function(item, escape) {
return '<div>'+ escape(item.sku) + ': ' + escape(item.name) + '</div>';
}
},
load: function(query, callback) {
if (!query.length) return callback();
$.ajax({
url: '/buying/products-search',
type: 'GET',
dataType: 'json',
data: {
q: query
},
error: function() {
callback();
},
success: function(res) {
callback(res);
}
});
},
onItemAdd: function(value, $item) {
// DO the thing
console.log($item);
}
});
SelectizeJS site: http://selectize.github.io/selectize.js/

a hack to solve your problem : inside onItemAdd function you can access all your JSON : this.options gives you all the selectize options, so now you have the value and the complete JSON, you can easily find back the item in your json that corresponds to the value selected. I can complete my answer if you provide a use case in plunker.

Related

How to save, load and delete from database using a single ExtJS model?

Using ExtJS 6 one can have a store bind to the model and use the methods sync to save or load to load data.
I imagine that if a data is removed from store, upon calling sync the data will be removed from database too.
In my use case, I have different URLs and mandatory Ajax query fields for each action of create/update, load and delete data.
I have only seen examples showing load or save to storage, how can I declare the load, save and delete using Ajax in the same model?
Another doubt I have is that stores themselves can have a proxy, so they can perform those operations too, at least the load operation that I have seen in use. What's the difference between having these on the model or store? What's the best practice?
Example model from Sencha docs (is this only for read?):
Ext.define('MyApp.model.Base', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type: 'int'
}],
schema: {
namespace: 'MyApp.model', // generate auto entityName
proxy: { // Ext.util.ObjectTemplate
type: 'ajax',
url: '{entityName}.json',
reader: {
type: 'json',
rootProperty: '{entityName:lowercase}'
}
}
}
});
Another example I found on https://examples.sencha.com/extjs/6.0.1/examples/classic/writer/writer.html using the proxy config, this seems more like what I would need as it specifies a URL for each operation:
var store = Ext.create('Ext.data.Store', {
model: 'Writer.Person',
autoLoad: true,
autoSync: true,
proxy: {
type: 'ajax',
api: {
read: 'app.php/users/view',
create: 'app.php/users/create',
update: 'app.php/users/update',
destroy: 'app.php/users/destroy'
},
reader: {
type: 'json',
successProperty: 'success',
root: 'data',
messageProperty: 'message'
},
writer: {
type: 'json',
writeAllFields: false,
root: 'data'
},
listeners: {
exception: function(proxy, response, operation){
Ext.MessageBox.show({
title: 'REMOTE EXCEPTION',
msg: operation.getError(),
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
}
}
},
listeners: {
write: function(proxy, operation){
if (operation.action == 'destroy') {
main.child('#form').setActiveRecord(null);
}
Ext.example.msg(operation.action, operation.getResultSet().message);
}
}
});
I believe I can have something like this in my case (this is just an example not tested!):
Ext.define('My.Person.Model', {
proxy: {
type: 'ajax',
api: {
read: 'http://myapiserver/getuser',
create: 'http://myapiserver/upsertuser',
update: 'http://myapiserver/upsertuser',
destroy: 'http://myapiserver/removeuser'
},
reader: {
type: 'json',
successProperty: 'success',
root: 'data',
messageProperty: 'message'
},
writer: {
type: 'json',
writeAllFields: false,
root: 'data'
},
// How can I have the parameters for each one?
extraParams : {
isuserUnderage : ' '
, query : '%'
}
}
});
I have no idea how to do this, specially specifying parameters for each type of Ajax request (read, create, update, destroy), I can have an upsert request that will send all fields, but the remove request will require only the ID, the get request can have optional fields for filtering, like filtering persons by name.
Example to be more clear of the problem.
Example data:
[
{
"id": "1",
"name": "Fred",
"age": 21,
"sex": "m"
},
{
"id": "2",
"name": "Susan",
"age": 12,
"sex": "f"
},
{
"id": "3",
"name": "Marcus",
"age": 22,
"sex": "m"
},
{
"id": "4",
"name": "Alex",
"age": 32,
"sex": "m"
}
]
Endpoints example:
Endpoints have parameters, these are mandatory, this means that calling an enpoint without a parameter will cause a server error, also passing a parameter that is not specified will cause a server error! If a parameter is not necessary one can pass a string with a single whitespace .
To read:
Endpoint: http://myapiserver/getuser?query={query}
Name is a filter by name, for example http://myapiserver/getuser?query=fred will bring users with name that has the string fred.
To write, we usually have an upsert, so it works for both insert and update:
Endpoint: http://myapiserver/upsertuser?id={id}&name={name}&age={age}&sex={sex}
So to update we can pass the ID: http://myapiserver/upsertuser?id=1&name=Frederick&age=21&sex=m and to insert we pass an empty string for ID: http://myapiserver/upsertuser?id= &name=Maurice&age=41&sex=m
To remove:
Endpoint: http://myapiserver/removeuser?id={id}
Example: http://myapiserver/removeuser?id=1, removes person with ID 1.
Because you say it's mandatory to use GETs with query params, I would encourage you to rethink your tech stack because the RESTful verbs really make it more clear what your action is, and you remove the actual action from your URL routes. However, I know sometimes this is totally out of our control, so I'll try my best here... I have to say, I've never experienced something like this, so I don't know if what I'm showing here is a best practice.
I can't show a true implementation because Sencha Fiddle is a simple sandbox, not meant for actual server-side implementations. I'm also assuming that you're using the classic toolkit, but if you need it in modern, it's a fairly easy port that you can do.
I prefer the proxy inside of the model for several reasons... if I need to use this model in several different stores throughout my app, then each store will inherit the same proxy. If I want to use the same model, but I don't want its proxy, I can simply override it when defining the store. Also, if the proxy doesn't exist on the model, then the framework assumes what your URL should be, which doesn't work when I want to use models individually.
I think I've come up with what you're asking for in this Fiddle. Really the core of what you want is in GETUser.js.
// We need to create our own proxy that will handle this for us
Ext.define('AjaxGet', {
extend: 'Ext.data.proxy.Ajax',
alias: 'proxy.ajaxGet',
// Per your requirement, we want to send individual requests
batchActions: false,
createOperation: function (action, config) {
// This means we're doing an action against one of our records
if (config && config.records) {
if (action === 'destroy') {
config.params = config.records[0].getDeleteParams();
} else if (action === 'create' || action === 'update') {
config.params = config.records[0].getUpsertParams();
}
}
return this.callParent(arguments);
}
});
// This is the desired, "GET" User model that uses GETs and query params for all actions
Ext.define('GETUser', {
extend: 'Ext.data.Model',
idProperty: 'Id',
fields: [{
name: 'Name',
type: 'string'
}, {
name: 'Id',
type: 'int'
}, {
name: 'Age',
type: 'int'
}, {
name: 'Sex',
type: 'string'
}],
proxy: {
type: 'ajaxGet',
api: {
read: 'Users',
create: 'upsertuser',
update: 'upsertuser',
destroy: 'removeuser'
},
actionMethods: {
create: 'GET',
update: 'GET',
destroy: 'GET'
}
},
getUpsertParams: function () {
const data = this.getData();
// Means this record hasn't been saved, so we're in the CREATE state
if (this.phantom) {
// We don't want to send the ID with what the framework sets as the ID
data.Id = undefined;
}
return data;
},
getDeleteParams: function () {
return {
Id: this.get('Id')
};
}
});
So what I ended up doing was creating a custom proxy that overrides the createOperation method to check which operation we're doing... based on that operation, we use the methods in the model to retrieve the params we want to send to the API. You need actionMethods in the proxy because otherwise, they default to POSTs.

update parameters variable on change.search using bootgrid with structured-filter

I am using https://github.com/evoluteur/structured-filter and http://www.jquery-bootgrid.com/ to create an advanced search through ajax/php.
Initially the code works and returns the data from the php file, but when trying to use structured-filter to pass $_GET variables to the php file through the use of jquery-bootgrid I am struggling.
No matter what I try, the url it is posting to has no $_GET variables, I have tried $("#grid-data").bootgrid("reload"); but nothing changes.
It appears the params variable is just not updating.
Here is my jquery script in full:
<script type="text/javascript">
$(document).ready(function() {
$("#myFilter").structFilter({
fields: [{
type: "text",
id: "gamertag",
label: "Gamertag"
}, {
type: "text",
id: "name",
label: "Team Name"
}, {
type: "number",
id: "wagePerMatch",
label: "Wage Per Match"
}, {
type: "number",
id: "gamesRemaining",
label: "Contract Games Remanining"
}, {
type: "boolean",
id: "transferListed",
label: "Transfer Listed"
}
]
});
var params = "";
$("#myFilter").on("change.search", function(event) {
var params = $("#myFilter").structFilter("valUrl");
$("#grid-data").bootgrid("reload");
console.log(params); // works, returns params
});
$("#grid-data").bootgrid({
ajax: true,
url: function() {
return "/api/search.php?" + params; // params never updates?
}
});
});
</script>
Is there a way to update params in .bootgrid when it changes in $("#myFilter").on("change.search" as right now its only sending requests to /api/search.php? (missing the parameters)
Now i don't have to much reputation, i am unable to add comment on this,
Please check this below URL, hope this will help you
http://www.jquery-bootgrid.com/Documentation#events
if you are looking for append the rows in existing grid so you can use "append" as given in URL or if you want to update the whole table you can destory the table and re-create a "bootgrid" object with binding with the respective DOM id's

Select2 js Plugin Not able to select any option

I am using Select2.js(latest version) to implement tokenized tagging in my application. It is working fine except, I am not able to select any item from the suggestions.
I saw few answers in which it was mentioned that we need to include "id" in our configuration. it doesn't seems to be working for me.
My code is :
$("#interest").select2({ ajax: {
url: "get-interests",
dataType: 'json',
delay: 250,
data: function (params) {
return {
q: params.term, // search term
page: params.page
};
},
processResults: function (data, page) {
// parse the results into the format expected by Select2.
// since we are using custom formatting functions we do not need to
// alter the remote JSON data
return {
results: data
};
},
cache: true
},
escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
placeholder:{
id: "-1",
text: "Add your interest.."
} ,
tags: true,
tokenSeparators: [',', ' '],
id: function(data) {
alert(JSON.stringify(data));
return data.interestId;
},
templateResult: function(post) {
// return html markup for individual result item
var markup ="";
if(String(post.description) !== 'undefined') {
markup = '<p><b>' + post.text + '</b> : ' + post.description + '</p>';
} else {
markup = '<p><b>' + post.text + '</b></p>';
}
return markup;
},
formatSelection: function(post) {
// This shows up in the select box
return post.text;
}
What I am doing wrong in above configuration?
Contrary to the comment you placed in your code, with Select2 4.0 you do need to add code to the processResults function to convert the returned JSON data to objects with an id property. Normally, the objects should also have a text property, but they don't have to if you supply the templateResult and templateSelection functions.
I saw few answers in which it was mentioned that we need to include
"id" in our configuration. it doesn't seems to be working for me.
Those answers were correct for previous versions of Select2, but with with Select2 v4.0, the id function is no longer supported. See the "The id and text properties are strictly enforced" section on the the "4.0 Anouncement" page:
You can also remove the formatSelection function. With Select2 4.0 it should now be named templateSelection. That means it is not getting called for you, but you probably didn't notice that because your formatSelection function is just doing what is done by default anyway.
The processResults function should return an object with a results property, which is set to an array of objects. Those objects all need to have an id property (but they can have other properties too).
You don't show what your returned data looks like, but judging from your id and templateResult functions, it appears to be an array of objects with the following properties: interestId, text and description. In that case your processResults function could look something like this:
// This builds a new array of new objects.
processResults: function(data, page) {
return {
results: $.map(data, function(post) {
return {
id: post.interestId,
text: post.text,
description: post.description
};
})
};
},
Or this:
// This just adds an `id` property to the objects in the existing array.
processResults: function(data, page) {
$.each(data, function(i, post) {
post.id = post.interestId;
});
return { results: data };
},

ExtJS: return total rows/records in json store

I have a json store that returns values in json format. Now I need to get the number of rows/records in the json string but when I use store.getCount() function it returns 0, but the combobox is populated with rows, and when I use store.length I get undefined, probably because its not an array anymore, its returning from store, which is calling php script. Anyways, whats the best approach for this problem?
Try this out:
var myStore = Ext.extend(Ext.data.JsonStore, {
... config...,
count : 0,
listeners : {
load : function(){
this.count = this.getCount();
}
}
Ext.reg('myStore', myStore);
and then use inside panels:
items : [{
xtype : 'myStore',
id : 'myStoreId'
}]
Whenever you need to get the count then you can simply do this:
Ext.getCmp('myStoreId').count
Your Json response from server, can be something like this...
{
"total": 9999,
"success": true,
"users": [
{
"id": 1,
"name": "Foo",
"email": "foo#bar.com"
}
]
}
Then you can use reader: {
type : 'json',
root : 'users',
totalProperty : 'total',
successProperty: 'success'
} in your store object.
As from docs if your data source provided you can call getTotalCount to get dataset size.
If you use ajax proxy for the store, smth like
proxy : {
type : 'ajax',
url : 'YOUR URL',
reader : {
type : 'json',
root : 'NAME OF YOUR ROOT ELEMENT',
totalProperty : 'NAME OF YOUR TOTAL PROPERTY' // requiered for paging
}
}
and then load your store like
store.load();
There will be sent Ajax asynchronous request, so you should check count in callback like this
store.load({
callback : function(records, operation, success) {
console.log(this.getCount()); // count considering paging
console.log(this.getTotalCount()); // total size
// or even
console.log(records.length); // number of returned records = getCount()
}
});

Saving the whole EditorGrid with a single Ajax request

I would like to save an ExtJS (3.3.1) editorgrid with a single Ajax request.
I've created an editorgrid, based on an ArrayStore.
var store = new Ext.data.ArrayStore({
data: arrayData,
fields: [ 'id', 'qty', 'idService', 'idSubscription',
'description', 'vat', 'amount' ]
});
[...]
var grid = {
xtype: 'editorgrid',
store: store,
view: gridView,
colModel: colModel,
selModel: selModel,
stripeRows: true,
tbar: tbar,
autoHeight: true,
width: 872,
clicksToEdit: 1
};
I've created a Save button with the following handler:
app.inv.saveButtonHandler = function () {
var myForm = Ext.getCmp("formHeader").getForm();
if (!myForm.isValid()) {
Ext.MessageBox.alert('Form Not Submitted',
'Please complete the form and try again.');
return;
}
myForm.el.mask('Please wait', 'x-mask-loading');
Ext.Ajax.request({
params: {
idCustomer: myForm.findField("idCustomer").getValue(),
issueDate: myForm.findField("issueDate").getValue(),
documentType: myForm.findField("documentType").getValue(),
documentNumber: myForm.findField("documentNumber").getValue()
},
url: 'save-sales-document-action',
method: 'POST',
success: function (response, request) {
myForm.el.unmask();
Ext.MessageBox.alert('Success', 'Returned: ' + response.responseText);
},
failure: function (response, request) {
myForm.el.unmask();
Ext.MessageBox.alert('Failed', 'Returned: ' + response.responseText);
}
});
};
In other words, I can send form elements with a simple value, but I don't know how to send the whole data grid. I would like to send the whole data grid with a single Ajax request.
I've already used before the cell-by-cell saving method, but in this case I would prefer to save the whole grid in one go. I don't need help for the server-side part, that I will do in Java, only for the client-side JavaScript.
Can someone help? Thanks!
After a night sleep and still no answers, I made further tries and I can answer my own question. I will leave the question open anyway, in case someone knows a better way.
To solve my problem, I added the property "storeId: 'gridStore'" to the ArrayStore, so I could locate the store later with Ext.StoreMgr.lookup(), then, at saving time, I proceed to re-build an Array record by record in the following way:
var gridData = new Array();
Ext.storeMgr.lookup('gridStore').each(function (record) {
gridData.push(record.data);
});
The essential part is that I don't get the whole Record, but only the data field of it.
After I've an array with the data, the easy part is add it to the params of Ajax.request:
params: {
...
gridData: Ext.encode(gridData)
},
This finally works. All the data is encoded in a single field. Of course on the server it will have to be decoded.

Categories