Algolia facet filter by empty/null value - facet

Is there a way to filter hits by a property's value that is either null or an empty string?
i.e., show me all objects that do not have an author
facetFilters=author:null
facetFilters=author:''
Or include it in a list of OR values?
i.e., show me all objects with author set to Twain or that do not have an author
facetFilters=(author:Twain,author:null)
facetFilters=(author:Twain,author:'')

Unfortunately - as of today - Algolia doesn't support that. One work-around could be to push an extra value if it's null, like pushing author: 'unknown' that you could use to filter on.

Or, you could add a _tags value at index-time that you can use to filter later on:
const tags: string[] = [];
if (!obj.author) tags.push('no-author');
idx.saveObject({ ...obj, _tags: tags });
Then, you can filter by the tag later on like so:
const res = idx.search('', { filters: '_tags:no-author' });

Related

Vue: Setting Data by matching route query

I'm attempting to set data fields provided by an array based on the Vue Router query. For example, when someone lands on my website using example.com/?location=texas, I want to set the location data by an array.
An example the array:
locations {
{
slug: "texas",
tagline: "Welcome to Texas",
}, {
slug: "california",
tagline: "Welcome to California",
}
}
I know this should be done using a computed property, however I am unable to get anything functioning. I've tried simple tests like if (this.slug.location === "texas"), and I cannot get the location data to populate. I would also like to provide default data in case there are no route matches.
Any help is extremely appreciated!
Edit:
I can accomplish this in a very manual way. Right now, I'm setting the query in data by the following:
slug: this.$route.query.location
I can display specific text by doing something like:
h3(v-if="slug === 'texas'") This will show for texas
h3(v-else-if="slug === 'california'") This will show for California
h3(v-else) This is default
The issue with this approach is there are various elements I need to customize depending on the slug. Is there any way I can create an array, and move whichever array matches a key in an array to the data??
You should be able to access a query param using the following (link to Vue Router documentation):
this.$route.query.location
So based on what you listed I would do something like...
export default {
computed: {
displayBasedOnLocationQueryParam() {
switch(this.$route.query.location) {
case 'texas':
return 'Welcome to Texas'
default:
return 'hello there, generic person'
}
}
}
}
Note that I'm not using your array explicitly there. The switch statement can be the sole source of that logic, if need be.

Getting id from row clicked on a dgrid List

I just started using dgrid, and going through the dTunes sample, I'm unable to find the id associated with each row in the list. This is pretty remedial on my part, but how would I also get the id I sent from the datasource?
define([
'require',
'dgrid/List',
'dgrid/OnDemandGrid',
'dgrid/Selection',
'dgrid/Keyboard',
'dgrid/extensions/ColumnHider',
'dojo/_base/declare',
'dojo/_base/array',
'dojo/Stateful',
'dojo/when',
'dstore/RequestMemory',
'put-selector/put',
'dojo/domReady!'
], function (require, List, Grid, Selection,
Keyboard, Hider, declare, arrayUtil, Stateful,
when, RequestMemory, put) {
var cstsNode = put(listNode, 'div#cstsCars');
...
var cstsList = new TunesList({}, cstsNode);
var dataCSTS = new RequestMemory({ target: require.toUrl('./dataCSTS.json') });
...
dataCSTS.fetch().then(function (cars) {
cstsCars = arrayUtil.map(cars, pickField('Description'));
cstsCars.unshift('All (' + cstsCars.length + ' CSTS Cars' + (cstsCars.length !== 1 ? 's' : '') + ')');
cstsList.renderArray(cstsCars);
});
...
cstsList.on('dgrid-select', function (event) {
var row = event.rows[0];
console.log(row.id); // shows row number. How do I get the real id or other fields?
console.log(row.data); // shows row text that is displayed ("sample text 1")
console.log(row.data.id); // undefined
});
Here is a snippet of sample data like I'm supplying:
[{"id":"221","Description":"sample text 1"},
{"id":"222","Description":"sample text 2"},
{"id":"223","Description":"sample text 3"}]
I'd like to see the id. Instead, row.id returns 1,2 and 3, ie the row numbers (or id dgrid created?).
You haven't really shown a complete example, but given that you're using a store anyway, you'd have a much easier time if you let dgrid manage querying the store for you. If you use dgrid/OnDemandList (or dgrid/List plus dgrid/extensions/Pagination), you can pass your dataCSTS store to the collection property, it will render it all for you, and it will properly pick up your IDs (since Memory, and RequestMemory by extension, default to using id as their identity property).
The most appropriate place to do what you're currently doing prior to renderArray would probably be in the renderRow method if you're just using List, not Grid. (The default in List just returns a div with a text node containing whatever is passed to it; you'll be passing an object, so you'd want to dig out whatever property you actually want to display, first.)
If you want a header row, consider setting showHeader: true and implementing renderHeader. (This is false in List by default, but Grid sets it to true and implements it.)
You might want to check out the Grids and Stores tutorial.
I think the problem might be that I was modeling my code based on the dTunes sample code, which has 3 lists that behave a little differently than a regular grid.
For now, I'm using the cachingStore that is available in the lists. So the way I get the id:
cstsList.on('dgrid-select', function (event) {
var row = event.rows[0];
var id = storeCSTS.cachingStore.data[row.id - 1].id; // -1 because a header was added
console.log(id);
});
I'm not sure whether this will work if I ever try to do sorting.

Using dgrid/dstore's REST store with a filter

I would like to extend dstore/Rest to take a parameter that is used to filter the store. This article suggests this is the desired method to alter the query of a dstore: http://www.sitepen.com/blog/2014/11/17/introducing-dstore/
Example:
new MyExtendedRestStore({color: 'red'});
I would like the internals of MyExtendedRestStore to alter the GET query so that color would now be set in the filter so any refresh calls would stick to adding color=red to the query. If I understand this correctly, it should also force the dstore/Trackable mixin to obey the filter.
In dgrid 0.4, instances using OnDemandList or Pagination can accept any collection - whether it be a root store, or a collection generated as a result of performing operations on that store. filter is one such operation.
In your case you state you want the grid to always show only red items, so you could very easily pass the grid a filtered collection, and no custom extension of Rest is required:
var TrackableRestStore = declare([ Rest, Trackable ]);
var store = new TrackableRestStore({ target: '...' });
var filteredCollection = store.filter({ color: 'red' });
var grid = new OnDemandGrid({
collection: filteredCollection,
columns: ...
});
This is also discussed towards the end of dgrid's Grids and Stores tutorial.

AngularJS: Take a single item from an array and add to scope

I have a ctrl that pulls a json array from an API. In my code I have an ng-repeat that loops through results.
This is for a PhoneGap mobile app and I'd like to take a single element from the array so that I can use it for the page title.
So... I'm wanting to use 'tool_type' outside of my ng-repeat.
Thanks in advance - I'm just not sure where to start on this one.
Example json data
[{ "entry_id":"241",
"title":"70041",
"url_title":"event-70041",
"status":"open",
"images_url":"http://DOMAIN.com/uploads/event_images/241/70041__small.jpg",
"application_details":"Cobalt tool bits are designed for machining work hardening alloys and other tough materials. They have increased water resistance and tool life. This improves performance and retention of the cutting edge.",
"product_sku":"70041",
"tool_type": "Toolbits",
"sort_group": "HSCo Toolbits",
"material":"HSCo8",
"pack_details":"Need Checking",
"discount_category":"102",
"finish":"P0 Bright Finish",
"series_description":"HSS CO FLAT TOOLBIT DIN4964"},
..... MORE .....
Ctrl to call API
// Factory to get products by category
app.factory("api_get_channel_entries_products", function ($resource) {
var catID = $.url().attr('relative').replace(/\D/g,'');
return $resource(
"http://DOMAIN.com/feeds/app_productlist/:cat_id",
{
cat_id: catID
}
);
});
// Get the list from the factory and put data into $scope.categories so it can be repeated
function productList ($scope, api_get_channel_entries_products, $compile) {
$scope.products_list = [];
// Get the current URL and then regex out everything except numbers - ie the entry id
$.url().attr('anchor').replace(/\D/g,'');
$scope.products_list = api_get_channel_entries_products.query();
}
Angular works as following:
Forgiving: expression evaluation is forgiving to undefined and null, unlike in JavaScript, >where trying to evaluate undefined properties can generate ReferenceError or TypeError.
http://code.angularjs.org/1.2.9/docs/guide/expression
so you only need to write:
<title>{{products_list[0].tool_type}}</title>
if there is a zero element the title will be the tool_type, if not, there is no title.
Assuming you want to select a random object from the list to use something like this should work:
$scope.product-tool_type = products_list[Math.floor(Math.random()*products_list.length)].tool_type
Then to display the result just use
<h1>{{product-tool_type}}</h1>
Or alternatively:
<h1>{{products_list[Math.floor(Math.random()*products_list.length)].tool_type}}</h1>

Search for an Item inside an Dojo Store

Is there any way to find an "item" inside an Dojo Store (Version 1.1!!).
The Format of the Json Data is like: name/id.
So far if tryed it with:
var storeItem = this.myFilteringSelect.store.fetch({query: {name: "Alpha"}});
But fetch does not return the item? Btw. i need the "ID" of the Item to set an default value for the filteringSelect (but the id can change from time to time...)
Let me preface my answer in that I can't speak to 1.1 specifically. But in 1.6...
store.fetch is coded in an asynchronous manner. It does not return the item. You must provide a callback that will iterate over the items returned from the query.
store.fetch({
query: {/*queryParams*/},
onComplete: function(items, findResult){
dojo.forEach(items, function(item){
// work with your item
}
}
});
https://dojotoolkit.org/reference-guide/1.6/dojo/data/api/Read.html#dojo-data-api-read
I don't believe this API had changed much over time, so if it is present in 1.1, then I think this should help.