Select2 custom data fetch when user starts typing in search bar. (BackboneJS / Marionette collection) SELECT2 - backbone.js

I am using SELECT2 in BackboneJS/Marionette. Right now following is flow:
Current:
From parent, call FETCH method of COLLECTION. When fetch is completed then send this COLLECTION to a new VIEW and display drop down (SELECT2)
New Requirement:
Now need to convert this data fetch at run-time. When user types in search bar of SELECT2, ajax call should be made and returned data needs to be converted to Marionette collection and then rendered in drop-down.
For this, i tried to implement this example.
Now problem is that data is fetched (visible in network tab), but drop-down remains empty (and there is no error/exception):
Added following code in _SELECTOR.prototype.settings.extend
ajax: {
url: API_PATH + "testingvalues2",
dataType: 'json',
delay: 1000,
minimumInputLength: 1,
cache: true,
data: function (params) {
var query = {
filter: params.term
};
console.log("query: ", query);
return query;
},
processResults: function (data) {
console.log("data : ", data);
console.log("this>>", this);
let newCollection = new DropdownDataCollection();
for(let dataItem of data){
let item = new DropdownValueEntity (dataItem);
newCollection.add(item);
}
return {results : newCollection};
}
},

Related

Kendo Grid Server Side filtering sending null as a filter object to the backend

Using Kendo AngularJS and ASP .NET MVC I am trying to send the filters object of a grid to the backend. However any filters made on the frontend are null in the request even though I set serverFiltering to true.
grid.dataSource = new kendo.data.DataSource({
serverFiltering: true,
transport: {
read: {
url: "api/foo",
dataType: "json",
type: "POST"
}
},
schema: {
data: "data", // records are returned in the "data" field of the response
total: "total"
}
});
//set grid to filterable
grid.filterable = {
mode: 'row',
operators: {
string: {
contains: "contains"
}
}
};
I took a look at a similar question but it did not help me as I wasn't able to replicate the solution listed as the accepted answer
On the controller side the "DataSourceRequest" mapped out the form values differently (e.g. inspecting the POST request on the frontend sent "filter" instead of "Filters" as an argument. I had to create a new model class that binded the proper values

Facebook like infinite scrolling

Will it be possible to implement facebook or linked in like infinite scrolling using EXT-JS API. I am aware of infinite grid although my requirement is to scroll panels infinitely just like facebook or linked in allows us. As of now I am working on EXT version 5.
Any link/white paper will greatly be appreciated.
Thanks in advance
Samir
You can use a dataview with a store tied to it to load the initial data in the wall. Then, in a controller add a listener to the scroll event and check when the scroll has reached the end.
I previously was creating a reddit app with that exact functionality though it was never completed/fully vetted. Here is a snippet of the scroll callback, basically I kicked off an ajax request and then load the returned data to the end of the current store's data:
mainPanelRendered: function () {
var p = Ext.ComponentQuery.query('yourDataView')[0];
var s = p.getStore();
//check on scroll if we've reached the end of the dataview
p.getTargetEl().on('scroll', function (e, t) {
var height = p.getTargetEl().getHeight();
if (height + t.scrollTop >= t.scrollHeight) { //Fire method to load more data to the store.
p.setLoading(true);
Ext.data.JsonP.request({
callbackKey:'jsonp',
url: s.proxy.url,
params: {
'count': 25,
'after': p.after
},
headers: { 'Content-type': 'text/json; charset=utf-8', 'Accepts': 'text/json' },
reader: {
type: 'json',
root: 'data.children',
successProperty: 'success'
},
success: function (response) {
p.after = response.data.after;
//now that you have more data add it to the store
Ext.each(response.data.children, function (article) {
var data = article.data;
try{
s.add({
id: data.id,
domain: data.domain,
subreddit: data.subreddit,
author: data.author,
over_18: data.over_18,
thumbnail: data.thumbnail,
subreddit_id: data.subreddit_id,
downs: data.downs,
ups: data.ups,
permalink: data.permalink,
name: data.name,
url: data.url,
title: data.title,
num_comments: data.num_comments,
score: data.score
});
} catch (ex) {
//do nothing the item already existed
}
//s.add(item);
//newItems[i] = item;
//i++;
});
p.setLoading(false);
//p.after = p.response.data.after;
}
});
}
});
},
And here is a link to my not-so-complete app's source. Again, it certainly isn't fully vetted but should give you an idea how you could add an infinite scroll. Checkout the mainPanel in the view and the render event in the controller.

Extjs update for all grid row not working

I am using Extjs 3.2grid.I have 5 Records.I am also stoping user to select multiple rows at a time.In grid i have button say approve.What i want is once user selects one record and clicks on approve the selected row coloumn "showRecord" will become 1 and remaing rows will become with showrecord:0
Here is my code
var proxy_surv = new Ext.data.HttpProxy({
type: 'ajax',
api : {
read : 'test/view.action?test='+testid_para+'&flag='+0,
create : 'test/create.action',
update : 'test/update.action',
destroy : 'test/delete.action'
}
});
var store_surv = new Ext.data.Store({
id : 'store_surv',
proxy : proxy_surv,
reader : reader,
autoSave : false
// <-- false would delay executing create, update, destroy
// requests until specifically told to do so with some [save]
// buton.
});
store_surv.on({
beforeload: {
fn: function (store, options) {
// Altering the proxy API should be done using the public
// method setApi.
store_surv.proxy.setApi('read', 'test/view.action?test='+testid_para+'&flag='+0);
}
}
});
And here is my logic
tbar: [{
iconCls: 'icon-user-add',
text: 'Approve',
handler: function(){
// Server hasn't returned yet for these two lines.
var survgrid=Ext.getCmp('grid_surv');
getstore =survgrid.getStore();
count =getstore.getCount();
var selected = survgrid.getSelectionModel().getSelected();
getstore.each(function(record){
if(parseInt(record.get('id'))==parseInt(selected.get('id')))
{
record.set('showRecord','1');
}
else
{
record.set('showRecord','0');
}
record.commit();
});
store_surv.save();
}
}
My problem is its not saving in database
don't use record.commit() it will say the record that all changes have been changed. it gets automatically called by store.sync(). remove record.commit() and it should work. you could also use 'record.save()' which will sync a single record.

How to Re-selecting row after store.load()

I have grid panel and a button.
when i click button it will transfer data via ajax and after finish grid will reload.
I try to re-selected row (in here i give u example is first row), but anyway it's not working
Ext.Ajax.request({
url: ...,
params: {
v: ...
},
success: function(response){
grid.store.load();
grid.getSelectionModel().select(0, true); // example first row
}
})
try selecting row in callback
grid.store.load({
scope:this,
callback:function(records, operation, success){
grid.getSelectionModel().select(0, true);
}
});
or
grid.store.load(function(records, operation, success){
grid.getSelectionModel().select(0, true);
});
You can make your row selections survive across store reloads by applying the following overrides:
Ext.override(Ext.view.View, {
preserveSelectionOnRefresh: true,
constructor: function() {
this.callOverridden(arguments);
if (this.preserveSelectionOnRefresh) {
this.mon(this.getStore(), {
beforeload: this.beforeStoreLoadPreserveSelectionRoutine,
scope: this
});
}
},
beforeStoreLoadPreserveSelectionRoutine: function() {
var sm = this.getSelectionModel(),
selection = sm.getSelection(),
i = 0,
l = selection.length,
savedSelection = [];
delete sm.savedSelection;
for (; i < l; i++) {
savedSelection.push(selection[i].getId());
}
if (savedSelection.length) {
sm.savedSelection = savedSelection;
}
}
});
Ext.override(Ext.selection.Model, {
refresh: function() {
// include selections saved across store reloads
if (this.savedSelection && this.savedSelection.length) {
var rs = [],
r,
j = 0,
l = this.savedSelection.length;
for (; j < l; j++) {
r = this.store.getById(this.savedSelection[j]);
if (r) {
rs.push(r);
}
}
if (rs.length) {
this.select(rs, false, true);
}
}
this.callOverridden();
delete this.savedSelection;
}
});
What they do is just saving what was selected before reloading the store and ensuring those records are selected again after the view is refreshed. Tested on Ext JS 4.1.2.
... and if you are using a buffered store and Ext JS 4.2+, you could use the scrollTo function, which selects AND scrolls the view to your selection:
grid.store.load(function(records, operation, success){
grid.view.bufferedRenderer.scrollTo(0, true);
});
select row after loading the store by adding a callback:
grid.store.load(function(records, operation, success) {
grid.getView().select(0);
});
grid.store.load ==> grid.store.on
http://bit.ly/1iBwb2i
On response, maybe you can use a field to differentiate it :
Sencha 4.0.7: store finde
store.find(fieldName, value);
Another way, but I think it isn't work after load store, it's use:
Sencha: getLastSelected
grid.getSelectionModel().getLastSelected()
Here is a plugin the takes care of that for you:
https://github.com/roberto-rodriguez/ExtJs_GridMultipageSelectionPlugin
The plugin keeps the selection across the pages in the pagination grid. Also includes a function named: getSelection() to the grid, which returns the an array with the ids of the selected rows.
The plugin assumes there is a column with dataIndex: 'id'
In case you want to select whatever was last selected (not just the first row as shown in the accepted answer) this is the simplest I think:
grid.store.load(function() {
var view = grid.getView(),
selModel = grid.getSelectionModel(),
lastSelected = selModel.getLastSelected();
view.select(lastSelected);
});
or better, a listener for all loading done by the store in the future:
grid.store.on('load', function() {
var view = grid.getView(),
selModel = grid.getSelectionModel(),
lastSelected = selModel.getLastSelected();
view.select(lastSelected);
});
grid.store.load();
We were having the same issue on Sencha 5.0.1. We found out this can be solved by adding an idProperty to your model. After that you can just call the reload() function on the store.
In your model:
idProperty: 'yourIdentifyingProperty',
Then
yourGrid.getStore().reload();
I'm not sure if you also have to bind the selection of the grid, but if the above doesn't work you could also try that.

Handling Subsidiary Views in Backbone.js

I have a basic Backbone application which obtain an array of JSON objects from a remote service and displays them: all good so far. However, each JSON object has an array of tags and I want to display the tags in a separate area of the webpage.
My question is: what is the most Backbone-friendly way of doing this? I could parse the existing data again in a second view, which is cleaner but takes up more computation (processing the entire array twice).
An alternative is gathering up the tag information in the primary view as it is working through the array and then passing it along to the subsidiary view, but then I'm linking the views together.
Finally, I'd like to filter based on those tags (so the tags will become toggle buttons and turning those buttons on/off will filter the information in the primary view); does this make any difference to how this should be laid out?
Bonus points for code snippets.
Hm. I'm not sure if this is the Backbone-friendly way, but I'll put the logic to retrieve a list of tags (I think that's what you meant by "parse") in the collection.
Both the main view and the subview will "listen" to the same collection, and the subview will just call collection.getTags() to get a list of tags it needs.
// Model that represents the list data
var ListDataModel = Backbone.Model.extend({
defaults: function() {
return {
name: null,
tags: []
};
}
});
// Collection of list data
var ListDataCollection = Backbone.Collection.extend({
model: ListDataModel,
initialize: function() {
var me = this;
// Expires tag collection on reset/change
this.on('reset', this.expireTagCache, this);
this.on('change', this.expireTagCache, this);
},
/**
* Expires tag cache
* #private
*/
expireTagCache: function() {
this._cachedTags = null;
},
/**
* Retrieves an array of tags in collection
*
* #return {Array}
*/
getTags: function() {
if (this._cachedTags === null) {
this._cachedTags = _.union.apply(this, this.pluck('tags'));
}
return this._cachedTags;
},
sync: function(method, model, options) {
if (method === 'read') {
var me = this;
// Make an XHR request to get data for this demo
Backbone.ajax({
url: '/echo/json/',
method: 'POST',
data: {
// Feed mock data into JSFiddle's mock XHR response
json: JSON.stringify([
{ id: 1, name: 'one', tags: [ 'number', 'first', 'odd' ] },
{ id: 2, name: 'two', tags: [ 'number', 'even' ] },
{ id: 3, name: 'a', tags: [ 'alphabet', 'first' ] }
]),
},
success: function(resp) {
options.success(me, resp, options);
},
error: function() {
if (options.error) {
options.error();
}
}
});
}
else {
// Call the default sync method for other sync method
Backbone.Collection.prototype.sync.apply(this, arguments);
}
}
});
var listColl = new ListDataCollection();
listColl.fetch({
success: function() {
console.log(listColl.getTags());
}
});
I guess two reasons for handling this in the collection:
It keeps the View code cleaner (This is given that we are not doing very complex logic in the tag extraction - It's just a simple _.pluck() and _.union().
It has 0 business logic involved - It can arguably belong to the data layer.
To address the performance issue:
It does go through the collection twice - However, if the amont of data you are consuming is too much for the client to process even in this case, you may want to consider asking the Backend to provide an API endpoint for this. (Even 500 pieces of data with a total of 1000 tags shouldn't bee too much for a somewhat modern browser to handle nowadays.)
Hmm. Does this help?
JSFiddle to go with this with the collection and the model: http://jsfiddle.net/dashk/G8LaB/ (And, a log statement to demonstrate the result of .getTags()).

Resources