setting initial facet/refinement values when using instantsearch.js - algolia

I'm using instantsearch.js and a combination of widgets to display my search results (pretty much modeled exactly after the demos).
I need to set some initial values for facets so certain items are filtered on by default. How do I do this? I know the AlgoliaSearchHelper (helper) object has a method toggleRefinement that should allow me to do this but I can't seem to access this helper prior to calling search.start() which does the initial query.
Any advice or insight on how to set some default refinements would be appreciated. Thanks.
Update: This isn't a duplicate - my issue seems to have been with the instantsearch.widget.toggle. It looks like this widget sets default values behind the scenes before the initial search. I've adjusted my code to not use this widget and to just set the searchParameters.tagFilters property instead. It was the toggle widget throwing things off for me as I couldn't figure out how to override its default filtering.

The easiest way to add initial filters to your instantsearch.js instance is to use an extra custom widget:
var search = instantsearch({
appId: 'YourApplicationID',
apiKey: 'YourSearchOnlyAPIKey',
indexName: 'YourIndexName'
});
search.addWidget(
instantsearch.widgets.searchBox({
container: '#search-box',
placeholder: 'Search for FIXME...'
})
);
search.addWidget(
instantsearch.widgets.hits({
container: '#hits-container',
templates: {
item: 'Hit {{objectID}}: FIXME'
}
})
);
// setup initial filters
search.addWidget({
init: function(options) {
// use options.helper (https://github.com/algolia/algoliasearch-helper-js) to initialize the search with custom filters & parameters
options.helper.addFacetRefinement('MyFacet', 'my value');
}
});
search.start();

This is what worked for us:
search.addWidgets([{
init: function(options) {
options.helper.toggleRefinement('attribute', 'value');
}
}]);

My issue seems to have been with the instantsearch.widget.toggle. It looks like this widget sets default values behind the scenes before the initial search. I've adjusted my code to not use this widget and to just set the searchParameters.tagFilters property instead. It was the toggle widget throwing things off for me as I couldn't figure out how to override its default filtering.

You are indeed right, under the hood the toggle widget uses the off value if provided:
if (userValues.off === undefined) {
return;
}
// Add filtering on the 'off' value if set
let isRefined = state.isFacetRefined(attributeName, userValues.on);
if (!isRefined) {
helper.addFacetRefinement(attributeName, userValues.off);
}
To avoid this incomprehension from other users, there is now a PR on instantsearch.js with the following update:
Note that if you provide an "off" option, it will be refined at initialization.

Related

The whole content widget is forcefully hidden when some parts are not visible in the editor

I am using view zone with content widget combination to show custom widgets below the code in the editor. As I can see, the visibility style is forcefully set to hidden if the bounds of the widget are not fully visible in the editor. Is there a way to disable this behavior? Maybe the view zone with content widget combination is not the correct approach at all... If that is the case, could someone please advise? I got the idea from code lens.
I have managed to work around it with a MutationObserver. Something like this did the trick for me:
const observer = new MutationObserver((mutations: MutationRecord[], observer: MutationObserver) => {
mutations.forEach((mutation) => {
if (mutation.attributeName && mutation.attributeName === 'style') {
if (contentWidget.style.visibility === 'hidden') {
contentWidget.style.visibility = 'inherit';
}
}
})
});
observer.observe(contentWidget, {
attributes: true
});

Find out if a leaflet control has already been added to the map

I wrote a custom Leaflet control. It's some kind of legend that may be added for each layer. The control itself has a close button to remove it from the map (like a popup).
The control can be added by clicking a button.
My problem is that the user may add the same control to the map several times. So what I need is to test if this specific control has already been added to the map and, if so, don't add it again.
I create a control for each layer, passing some options
var control = L.control.customControl(mylayer);
and add it to my map on button click
control.addTo(map);
Now imagine the control has a close button and may be closed. Now if the user clicks the button again, I only want to add the control if it's not already on the map - something like this (hasControl is pseudocode, there is afaik no such function)
if(!(map.hasControl(control))) {
control.addTo(map);
}
For simplicity I made an example where I create a zoom control and add it twice here.
Easiest way is to check for the existence of the _map property on your control instance:
var customControl = new L.Control.Custom();
console.log(customControl._map); // undefined
map.addControl(customControl);
console.log(customControl._map); // returns map instance
But please keep in mind, when using the _map property, that the _ prefix of the property implies that it's a private property, which you are normally not supposed to use. It could be changed or removed in future versions of Leaflet. You're not going to encounter that if you use the follow approach:
Attaching a reference of your custom control to your L.Map instance:
L.Control.Custom = L.Control.extend({
options: {
position: 'bottomleft'
},
onAdd: function (map) {
// Add reference to map
map.customControl = this;
return L.DomUtil.create('div', 'my-custom-control');
},
onRemove: function (map) {
// Remove reference from map
delete map.customControl;
}
});
Now you can check for the reference on your map instance like so:
if (map.customControl) { ... }
Or create a method and include it in L.Map:
L.Map.include({
hasCustomControl: function () {
return (this.customControl) ? true : false;
}
});
That would work like this:
var customControl = new L.Control.Custom();
map.addControl(customControl);
map.hasCustomControl(); // returns true
map.removeControl(customControl);
map.hasCustomControl(); // returns false
Here's a demo of the concept on Plunker: http://plnkr.co/edit/nH8pZzkB1TzuTk1rnrF0?p=preview

how to add two different selection models in extjs panel

I have a grid with a customized selModel and cellediting plugin. Now I need to add also Checkbox Selection Model to it. Is this possible to have two selModels? Here is my existing code
selModel: Ext.create('TTT.MultiCellSelectionModel', {
mode: 'MULTI',
allowDeselect: true
}),
multiSelect: true,
selType: 'cellmodel'
as far as i know its not possible for grid having more than one SelectionModel.
but it could be done if you override or make new SelectionModel class which have your requirement.
Ext.define('TTT.CustomSelectionModel', {
extend: 'TTT.MultiCellSelectionModel',
// you can put your logic here
})
But you will need extra time for it.

Create jQuery ui resizable instance using selector added to DOM by jQuery

I'm trying to start a jquery ui resizable instance, but using a selector added to the DOM by jquery itself. This is a basic example of my script:
HTML:
<div class='lyr'></div>
jQuery:
// Add class
$('lyr').addClass('fixed');
// Resizable
$('.fixed').resizable({
aspectRatio: true,
handles: 'all'
});
I've thought about using something along the lines of live() or bind() but I have no event to bind to. Any help appreciated.
I have used the LiveQuery plugin - http://brandonaaron.net/code/livequery/docs in the past to be able to target elements added to the dom, like in your case.
If I've got this right, you want anything on the page which has the class "fixed" to be resizable, even if the class is added after the page has loaded? You're right that live, bind and delegate won't help here.
I can think of two possibilities, neither lovely.
First, set up a live "mouseenter" event which will make the element resizable if it wasn't before:
$(body).delegate(".fixed", "mouseenter", function(ev) {
var target = $(ev.target);
if (target.data("resizable")) return;
target.resizable({
aspectRatio: true,
handles: 'all'
});
})
This gets us round the problem of having no event to bind to.
Alternatively, you could monkeypatch jQuery.fn.addClass:
var classRe = new RegExp(c + className + \b);
._addClass = jQuery.fn.addClass;
jQuery.fn.addClass = function(className) {
if (classRe.test(classname)) {
if (this.data("resizable")) return;
this.resizable({
aspectRatio: true,
handles: 'all'
});
}
jQuery.fn._addClass.apply(this, arguments);
}
Of course this will only work if the class is added through the addClass method.
Also in your example,
$('lyr').addClass('fixed');
Should probably be:
$('.lyr').addClass('fixed');

How do I dynamically add a Dijit widget to a Dojo form?

I'm trying to add a new FilteringSelect widget dynamically to a preexisting form I made out of declarative tags (on page load).
prereqs = 0;
function addAnotherPrerequisite(){
var newPreReqCursor = dijit.byId("Prerequisite"+(prereqs-1)).domNode;
dojo.create("input",{
id:"prerequisite"+prereqs,
jsId:"Prerequisite"+prereqs,
dojoType:"dijit.form.FilteringSelect",
store:"PrerequisitesStore",
searchAttr:"name",
style:"width: 350px;",
required:"true",
class: "appendedPreReq"},newPreReqCursor,"after");
dojo.parser.parse( newPreReqCursor.parentNode );
prereqs++;
}
This code properly builds a FilteringSelect widget, but the widget does not seem to be registered with the form. Whenever I submit the form, none of the values in the new widgets appear. The validation attribute works, though, and it properly pulls the values from the store.I can even call the new widget via its jsId(Prerequisite1, Prerequisite2, etc) It just won't POST!
Instead of dojo.create I also tried called the FilteringSelect widget directly. This also made the widget, but did not register the values with the form during POSTing.
var filteringSelect = new dijit.form.FilteringSelect({
id: "prereq"+prereqs,
jsId: "Prerequisite"+prereqs,
store: PrerequisitesStore,
searchAttr: "name",
required: true,
style: 'width: 350px;',
class: 'appendedPreReq'
},
"prerequisite"+prereqs).startup();
I'm going crazy trying to figure this out.
So it looks like there's some sort of bug or something. I had to define the 'name' attribute explicitly to get the widget to show up in my form's .getDependents() method. That's how dijit.forms gets its list of form values. After doing this I also couldn't access this widget by dijit.byId (didn't return anything, silently caught the error I guess), so I returned the object via its jsId with an eval.
prereqs = 0;
function(){
var newPreReqCursor = eval("Prerequisite"+(prereqs-1));
newPreReqCursor = newPreReqCursor.domNode;
dojo.create("input",{
id:"Prerequisite"+prereqs,
name:"Prerequisite"+prereqs,
jsId:"Prerequisite"+prereqs,
dojoType:"dijit.form.FilteringSelect",
store:"PrerequisitesStore",
searchAttr:"name",
style:"width: 350px;",
required:"true",
class: "appendedPreReq"},newPreReqCursor,"after");
var filterSelect = dojo.parser.parse( newPreReqCursor.parentNode );
}
It is very easy. Just create a new object like that:
// first let's create an empty node (you can reuse the existing one)
var node = dojo.create("div", {
// all necessary node attributes
className: "appendedPreReq",
style: {
width: "350px"
}
}, "myAnchorNodeId", "after");
// now let's create a widget
var widget = new dijit.form.FilteringSelect(
{
// all necessary widget properties
id: "prereq" + prereqs,
store: PrerequisitesStore,
searchAttr: "name",
required: true
},
node // optional node to replace with the widget
);
Read all about it:
http://docs.dojocampus.org/dijit/info
http://docs.dojocampus.org/dijit/form/FilteringSelect
yes while creating widgets as said by Eugene Lazutkin the input type hidden related with the filtering select gets the name as of the id, and also the value of the hidden field is updating correctly. But when the filtering select is created thr .create() method we need to give the name , and also the value of the hidden field is not updating after we select some values from the filtering select(even when we blur out). Eugene Lazutkin can you let me know why its happening so... how to update the value of hidden field in the .create() method.