Algolia Instantsearch with Multiple Indices and Multiple Pagination Widgets - pagination

I have implemented instantsearch.js with 1 search input and multiple indices, and multiple stats/pagination widgets. Everything seems to be working correctly except for the pagination widgets.
Here is a codepen https://codepen.io/flrrrhoffpauir/pen/EEpWre
collections.addWidget(
instantsearch.widgets.pagination({
container: '#collections-search-pagination',
showFirstLast: false,
labels: {
next: '>',
previous: '<',
},
cssClasses: {
root: 'search-pagination'
}
})
}
search.addWidget(
instantsearch.widgets.pagination({
container: '#stories-search-pagination',
showFirstLast: false,
labels: {
next: '>',
previous: '<',
},
cssClasses: {
root: 'search-pagination'
}
})
}
If you search for ‘martin’ and then click the Stories tab, you can see the results and that the pagination is working. If you now click the Collections tab, you can see that the pagination widget has the correct number of pages based on how many results were returned according to the stats widget, but then you click to go to page 2, you are just scrolled to the top of the page and it doesn’t load the page 2 data.
How can I get two or more pagination widgets on the page at once that both work correctly?
This is what I went off of to create the multiple index search, but they don't cover multiple pagination widgets: https://jsfiddle.net/j9nwpz34/49/

The searchFunction implementation should transfer all the information that needs to be synchronized. For example, in your case you have a pagination widget that you want to sync across instances of InstantSearch, so you want to transfer the pagination property on top of the query parameter.
var search = instantsearch(
{
/* appId: '',
apiKey: '',
indexName: 'movies',*/
searchFunction: function(helper) {
var query = movies.helper.state.query;
var page = movies.helper.state.page;
products.helper.setQuery(query);
products.helper.setPage(page)
products.helper.search();
helper.search();
},
searchParameters: {
hitsPerPage: 3
}
});
I've modified the JSFiddle to match your need. You can learn more about this state by going to the JS Helper documentation (internal state management of InstantSearch.js).
Update based on the jsFiddle provided:
The rest of the example still holds. However, one thing to note is that if you make a modification in the helper, it will reset the page. In the provided fiddle, you do such a change in the collections searchFunction. You will always set the query, which will always reset the page to 0. Hence the bug.
Here is a fixed fiddle

Related

Problems with v-select and data

Good afternoon friends, then I'm going to tell you my mistake. I am working for a users screen, where you have your registration and editing. When you enter the register section you don't have to show the role you already have in the database. But on the edit screen, it already has a role assigned, so I would have to bring it to it (as it does with the text-fields) But I can't get it to load them.
attached images of the screen:
When I do a debugger as soon as I enter the screen, I realize that it is returning the roles as an array. And it shows me the role well, but it doesn't place it in the select.
Attached image of the error, below the images is the code that I use.
<v-select
label="Rol"
v-model="form.rolId"
:items="roles"
item-value="value"
item-text="text"
:rules="[(v) => !!v || 'Este campo es requiredo']"
required
>
</v-select>
data() {
return {
form: {},
roles: [
{ value: "Agente", text: "Agente" },
{ value: "Administrador", text: "Administrador" },
],
};
},
You have to put a default value on your v-model for it to load the data in the select.
see codepen here

CouchDB/PouchDB Selectors not syncing properly

I have set up a selector and my pouchDB syncs documents based on that selector.
Here is the selector. It will get all documents of type="job" and that include 1371 ID in permission array OR any document of type="load".
const myselector = {
$or: [
{
type: {
$eq: 'job'
},
permission: {
$elemMatch: { $eq: 1371 }
}
},
{
type: {
$eq: 'load'
}
}
]}
Here's how I sync
this.db.replicate
.from(this.remoteDB, {
selector: myselector
})
.on('complete', info => {
// then two-way, continuous, retriable sync
this.db
.sync(this.remoteDB, {
live: true,
retry: true,
selector: myselector
})
.on('change', change => {
console.log('my change0', change);
})
.on('error', error => {
console.log('my error', error);
});
})
.on('error', error => {
console.log('my error2', error);
});
This works perfectly and tells me if theres a change in any document but If e.g I make a change in permissions array and id 1371 gets changed then it doesnot notify me of the change. Now if I change any other field in that document, it doesnot get replicated as its not been synced anymore.
I'm using Selector instead of CouchDB Filters as they're apparently 10x faster but this sync becomes a problem.
If the document gets changed and doesnot fall in the selector criteria anymore then the change function is not called.
The behaviour you described is correct.
The filtered changes feed only includes the documents that currently match the selector conditions. The filtering is not considering the previous state of the document.
This question exposes a similar issue: CouchDB filter function and continuous feed
I see 2 approaches to manage this:
Make filtering data part of the document identity:
Design your docs by including the filtering attributes as part of the document IDs, so the change of any of the filtering attributes should be managed as a deletion and a creation of a new document. The local database will contain only the valid documents.
Keep history of the filtering data in the doc:
You should keep the history of the values of the filtering attributes in the documents and expand your selector to check the current and old values. In this case, is your client application the responsible to determine which of the documents in the local database are valid in a moment as not every document in the local database is valid for the client.

Buildfire - How to load sorted pages dynamically from publicData/datastore

I am trying to lazy load data from publicData using the options that BuildFire describes in the wiki. I have set up some code to test that it works and it seems that is does not any way that I configure the request options. Here is the code that I am using:
var loadSortedPages = function(page) {
var skip = page*50;
var options = {
"filter": {},
"sort": {"points": 1},
"pageSize": "50",
"skip": skip.toString()
}
buildfire.publicData.search(options, 'users', function(err, records) {
console.log("RECORDS SORTED ASCENDING BY POINTS FOR PAGE " + page, records);
});
}
loadSortedPages(0);
loadSortedPages(1);
loadSortedPages(2);
I have tried, it seems, every thinkable combination of "page" and "skip" both as different combinations of string and number values. Nothing works and I always get back the first 50 sorted records for each of the loadSortedPages calls even though I am passing in different page numbers. If this something on BuildFire's end?
Here is the documentation on how to use Datastore search https://github.com/BuildFire/sdk/wiki/How-to-use-Datastore#buildfiredatastoresearchoptions-tag-optional-callback
It seems like you are mixing to pagination methods:
and for pagination you can either use:
page : is number that determine the page that need to retrieve.
pageSize: is a number of record per page , the max value is 20.
Or use:
skip : is number of record that you need to skip.
limit: is a number
of record for this call, the max value is 20.

jqGrid Applying postdata filters in grid create ODD behavior

I am seeing two different behaviors and not sure why. Parts of the question are result of testing solutions implemented from other Q & A.
Summarized Grid create(I only included properties pertinent to question)...
grid setup1
url: jqDataUrl,
datatype: "json",
mtype: "GET",
//loadonce: true
// Default sorting
sortname: typeof prefs.sortCol !== "undefined" ? prefs.sortCol : "LastName",
sortorder: typeof prefs.sortCol !== "undefined" ? prefs.sortOrd : "asc",
sorttype: "text",
sortable: true,
postData: { filters: JSON.stringify({ "groupOp": "AND", "rules": [{ "field": "FirstName", "op": "cn", "data": "max" }]})},
search: true,
results 1 with search: true
When the above grid first loads, it loads with filtered results from postdata filters. If I go to edit url of a resulting row and come back, the record in grid not updated, even though the page/grid above is reloading from scratch from server.
grid setup 2
//same as above but
search: false
results 2 with search: false
When the grid loads this time, the filter not applied. If I go to edit url of a row and come back, the record is updated.
I've read a lot of posts about setting loadonce: true, and changing datatype from local to json and json to local for refreshing, but what I want is for the grid to always load, sort and filter from server data.
Although I understand that free jqGrid does things better, unfortunately, I cannot replace current jqGrid.js file.
My question is two part:
1) I do not see search as an option on wiki here so where is it defined.
2) Can and how do I get the postdata filters to apply on load AND my records updated on the grid after edit?
To answer my own questions:
1) search:true will send _search==true in the http request.
2) The postdata filters(aka where clause when querying data) was being sent in the http request, however, my controller was performing different operations based upon the search: value(aka _search) parsed from http request.
Inside my controller I was setting another property based upon the _search value, and the controller's property was then used to determine whether or not to refresh grid data or use session. It was using session and thus did not update my filtered results after edit.
Another issue I found, was that if I had search:true and manually reset postdata filters to {}, my controller had an error(non thrown w/o try/catch) when it tried to setup the linq with a null, and exited out of grid setup and displayed nothing.

Do I have two instances of the same store?

i populate a listview using a store with jsonp proxy that sends a GET request to my server. when the app launches the request is send and the list items are rendered with the response as they should. now when i then manually add a new item in my data-base server and refresh the list with the code shown in the controller below and inspect the store object in the console i can see that the newly created item is in the store data. so far so good, everything as expected. however, the new item is not in the refreshed in the list. the strange thing is that when i inspect the list object and its containing store object the newly created item is not included. However when i relaunch the app (rather than reload the store and refresh the list) new newly created item appears in the list. to me it seems that somehow i have 2 store instances, one with the new data (which i retreive with Ext.getStore) and one without (the one inside the listview) which i thought should be actually the same. how is that possible? below i show you how i do the thing. Any help is greatly appreciated.
the controller
Ext.define('VB1.controller.ListController', {
extend: 'Ext.app.Controller',
config: {
refs: {
listView: 'listview',
refreshButtonTap: '#refreshbutton',
},
control: {
refreshButtonTap: {
onRefreshList: 'refreshList',
},
}
},
launch: function () {
this.callParent(arguments);
Ext.getStore('MyStore').addListener('load', 'recordLoaded', this);
},
refreshList: function () {
var loadedStore = Ext.getStore('MyStore').load();
console.log(loadedStore) //here the new item is included
},
recordLoaded: function () {
var list = this.getListView();
list.refresh();
console.log(list) //here the new item is not included in the store object inside
//listobject
}
});
the Store
Ext.define('VB1.store.MyStore', {
extend: 'Ext.data.Store',
alias: 'widget.mystore',
config: {
model: 'VB1.model.MyModel',
autoLoad: true,
proxy: {
type: 'jsonp',
url : 'myUrl.js',
enablePagingParams: false,
reader: {
type: 'json',
rootProperty: 'array.resources'
},
},
},
});
the listview
Ext.define('VB1.view.ListView', {
extend: 'Ext.dataview.List',
alias: 'widget.listview',
requires: [
'Ext.dataview.List',
],
scrollable: 'vertical',
config: {
loadingText: "loading...",
emptyText: '</pre><div class="notes-list-empty-text">No notes found.</div><pre>',
itemTpl: '</pre><div class="list-item-title">{title}</div><div class="list-item-narrative"><img src="{listlogo}"/></div><pre>',
},
listeners: {
itemtap: function(list, index, item, record) {
this.fireEvent('showDetails', record, this);
}
},
});
this is how i add the list including the store to the viewport at app launch
var listView = {
xtype: 'listview',
store: {xtype: 'mystore'},
}
Ext.Viewport.add(listView);
I just found out what the problem was. first of all the store was instantiated 2 times as I suspected. obviously one time by the app and another time by the view. hence i ended up with having two stores. since i did not set a storeID the stores became identified by two unique ids based on the xtype name i have given in the alias config of the store.
the store i resolved and logged in the controller like below had the id ex-mystore-1
var loadedStore = Ext.getStore('MyStore').load();
console.log(loadedStore) //here the new item was included
and the store inside the list view object got the id ext-mystore-2
var list = this.getListView();
console.log(list._store); //here the new item was not included
what changed the hole problem in my favor was when i added a storeId to the store. after that i still had two stores, however, with the same storeIds (but with with different unique or observable ids). the good new was that now the new item was included in both store instances. i also was able to get rid of the second store instance by not instantiating the xtype of the store in the listview but reference it by storeID. Now everything works as it should. thanks to anybody who looked at this. i hope this helpes somebody who finds similar trouble.

Resources