Pass Dynamic Variable to highlightResults in Autocomplete.js - autocomplete

I'm building a typeahead component for my Vue application that searches Algolia, which has several different indexes to search in different places, so I've created props to be passed in to set the input placeholder, search index, and displayKey.
All works well except my highlighting function for suggestions.
I'm sure this is something simple but I can't get the highlight return to pick up the dynamic prop passed in.
$('.typeahead').autocomplete({ hint: false }, [{
source: $.fn.autocomplete.sources.hits(this.client, { hitsPerPage: 5 }),
displayKey: this.display,
templates: {
suggestion: (suggestion) => {
return suggestion._highlightResult.{this.display goes here}.value;
}
}
}]).on('autocomplete:selected', (event, suggestion, dataset) => {
console.log(suggestion, dataset);
})
If I omit the highlighting all works perfectly.

I knew it was simple, call it via array key instead of dot notation.
return suggestion._highlightResult[this.display].value;

Related

How to filter an array of object in Mui DataGrid?

I recently changed my tables to Mui-datagrid on Material UI 5, and I have a special use case with an array of objects. I want to enable the phone number filter in this column, but the number is provided as an object list.
phone: [
{ type: "home", number: "795-946-1806" },
{ type: "mobile", number: "850-781-8104" }
]
I was expecting a 'customFilterAndSearch' or an option to customise how to search in this specific field.
customFilterAndSearch: (term, rowData) =>
!!rowData?.suppressedOptions.find(({ description }) =>
description?.toLowerCase().includes(term.toLowerCase())
),
I have made some tries with the filterOperators, but no success yet. I have made a full example here https://codesandbox.io/s/mui-data-grid-vs05fr?file=/demo.js
As far as I can see from the DataGrid documentation I don't see any way to change the filter function for a specific function.
Likely the best workaround for your use case will be converting this to a string be converting the data to a string before you pass it to the datagrid. Though you will lose the styling that you currently do by making the phone type bold.
On second though your best best would probably be to split the phone column into two columns which would probably be the cleanest way of solving your problem
Add helper function.
You could potentially add a helper function to just map all the phone lists to something like mobilePhone or homePhone
const mapPhoneObject = (rows) => {
rows.forEach((row) => {
row.phone.forEach((phone) => {
row[`${phone.type}Phone`] = phone.number;
});
});
return rows
};
I've added a fork of your snippet with my function, it is I think the most viable solution for your problem: https://codesandbox.io/s/mui-data-grid-forked-ppii8y

How can I test the content in ag-grid using testing-library?

I am trying to write a few simple tests that the headers and data I want to render are showing up as expected. I created a repo - https://github.com/olore/ag-grid-testing-library to reproduce. The table looks as I would expect when opened in a browser.
<AgGridReact
columnDefs={ /* First 2 always findable, others never */
[
{ field: "make" },
{ field: "model" },
{ field: "price" },
{ field: "color" },
]}
rowData={
[{
make: "Toyota",
model: "Celica",
price: "35000",
color: "blue"
}]
}
pagination={true}></AgGridReact>
And the tests
test('renders all the headers', async () => {
const { getByText } = render(<GridExample />);
expect(getByText("Make")).toBeInTheDocument(); // PASS
expect(getByText("Model")).toBeInTheDocument(); // PASS
expect(getByText("Price")).toBeInTheDocument(); // FAIL
expect(getByText("Color")).toBeInTheDocument(); // FAIL
});
Locally, the first 2 column headers and data are accessible, but none of the other columns are rendered, as I can see in the output of testing-library. I am using --env=jsdom-fourteen as recommended by other posts.
Strangely enough, no headers or data are rendered for the tests when in the codesandbox for this repo, as with local, the browser looks correct.
https://codesandbox.io/s/gallant-framework-e54c7. I then tried waiting for gridReady
https://codesandbox.io/s/intelligent-minsky-wl17y, but it didn't make a difference.
EDIT: Also tried directly calling a function in onGridReady, same problem (first 2 columns pass, second 2 fail)
test('renders all the headers', async (done) => {
let page;
const onReady = () => {
expect(page.getByText("Make")).toBeInTheDocument(); // PASS
expect(page.getByText("Model")).toBeInTheDocument(); // PASS
expect(page.getByText("Price")).toBeInTheDocument(); // FAIL
expect(page.getByText("Color")).toBeInTheDocument(); // FAIL
done();
}
page = render(<GridExample ready={onReady}/>);
});
ag-grid uses Column Virtualisation, so it seems the solution here is to disable it via the suppressColumnVirtualisation attribute on the <AgGridReact> element.
<AgGridReact
suppressColumnVirtualisation={true}
...
Boom! All the tests pass!
In reality, it's probably ideal to only suppress this during testing:
suppressColumnVirtualisation={process.env.NODE_ENV === "test"}
An addition to #olore's answer.
If you use server side data source, make sure
Your mock server responds with expected data, not error.
You use asynchronous selector in testing library, at least for the first cell of the row.
expect(await findByText('Price')).toBeInTheDocument();

KendoUI Autocomplete paging issue

I have a textbox bound to KendoUI autocomplete widget. The JS code looks like this:
var dataSourceImeSearch = {
type: "json",
transport: {
read: {
url: "#Url.Action("ImeSearch")",
contentType: "application/json; charset=utf-8",
type: "POST"
},
parameterMap: function (data, type) {
if (type == "read") {
if (data.filter) {
data = $.extend({ sort: null, filter: data.filter.filters[0] }, data);
} else {
data = $.extend({ sort: null, filter: null }, data);
}
return JSON.stringify(data);
} else {
return JSON.stringify({ model: data });
}
}
},
batch: false,
pageSize: 10,
serverPaging: true,
serverFiltering: true,
serverSorting: true,
schema: {
errors: "Errors",
data: "Data",
total: "TotalRecordCount",
model: myModel
},
error: function (e) {
if (e.errors) {
alert(e.errors);
}
}
};
$("#Ime").kendoAutoComplete({
dataTextField: "PunoIme",
filter: "contains",
minLength: 3,
dataSource: dataSourceImeSearch
});
I am experiencing a weird thing here. Autocomplete is working in terms that when I type the third character it runs to the server and gets JSON data back from there and shows first ten results. The thing is that this textbox is searching large datasets, so for some queries with say 4 characters result set can be more than 1000 items. For some reason the widget is not figuring out that there are more than 10 results and when I scroll down in the autocomplete dropdown which gets shown, it will not fire any search for a second page and so on. You can see that the serverPaging for data source is set to true, but this does not help.
Any help is appreciated. Thank you.
I found out after posting this question that Autocomplete widget does not allow paging by design. This was explained in the KendoUI forums by some Kendo employee as an example of poor UX (if you have autocomplete that needs paging). I would argue that, since in my opinion, the first use case of the autocomplete would be in case of a search of a person, and here I am doing exactly that. The only problem is that if you search by person's second name you can end up with hundreds of results after first 3 or 4 characters and you really need paging for that. If the Kendo people think that this is a case of a bad UX, this should be clearly mentioned in the Autocomplete documentation, and I could really not find any mentioning of it at a single place, and one would think that it might be a good idea to mention something like this to the people so that they don't have to waste all day trying to figure out what went wrong.
In my opinion one of the worst use case examples at all demos at KendoUI web demo pages is the Shared DataSource example, where if you type in 'ch' in the autocomplete textbox in the top, you will end up with 10 results in autocomplete, but 14 in the datagrid bellow. It really strikes me as stupid that nobody in Kendo sees this behavior as odd.
So my answer to my own question would be the following: DO NOT use autocomplete, except in some really really simple use case (I can't really think of a single one that would make sense). I ended up making a whole search form with 5 textboxes and search button in case where I hoped that I was going to be able to use 2 textboxes (one with autocomplete) and a search button.
You have set pageSize:10, which means that only 10 records are returned to the AutoComplete and its dataSource contains only 10 elements, I am afraid that automatic paging is not implemented by default

How to update a doc value from an iron-router function

I know this is a nood question, but I'm trying to work out how to update a value in a document from a route in iron router. I've found the spot I need to put the function, but I'm struggling with the mongo code needed to make it work.
I'm trying to increment a views element each time a link is clicked, so have added the following code to the route.
data: function () {
var project = projectDocs.findOne(this.params._id);
// need to increment views value by one
console.log(project.views);
projectDocs.update({id: project.id},
{$inc: {views: 1}}
);
console.log(project.views);
return project;
}
});
The project.views value is returning the correct value, but the code to update the value throws an exception at the moment.
I tried the simple thing of project.views++ which increments the variable within the function but it never gets pushed to the database (no surprises there I guess).
Can someone point me in the direction I need to get this value to inc (and is this even the right place to do this?).
Thanks.
Peter.
OK, I found this link that has lead me part of the way http://books.google.com.au/books?id=uGUKiNkKRJ0C&pg=PA37&lpg=PA37&dq=Cannot+apply+$inc+modifier+to+non-number&source=bl&ots=h7qyOddRsf&sig=EWFw9kNLGHoFEUS-nTNsBStDRcQ&hl=en&sa=X&ei=cRGXUse0DNGciAfk6YHgCA&ved=0CFcQ6AEwBQ#v=onepage&q=Cannot%20apply%20%24inc%20modifier%20to%20non-number&f=false which explains that you can only inc numeric values (I had this as a string it seems.
Now the problem is that I seem to be in an endless loop.
The function now looks like
this.route('projectPage', {
path: '/projects/:_id',
waitOn: function() {
return Meteor.subscribe('singleProject', this.params._id);
},
data: function () {
var project = projectDocs.findOne(this.params._id);
// need to increment views value by one
console.log("Views", project.views);
console.log("Project", project);
projectDocs.update(project._id,
{$inc: {views: 1}}
);
console.log(project.views);
return project;
}
});
Why would this be looping?
Use _id instead of id. So
projectDocs.update({_id: project._id},
{$inc: {views: 1}}
);
If that's not it, perhaps you could update your answer with whatever exception you are getting.
Just read the fantastic new documentation on iron-router a bit further and moved the $inc function to the unload hook and all seems to be good.
this.route('projectPage', {
path: '/projects/:_id',
waitOn: function() {
return Meteor.subscribe('singleProject', this.params._id);
},
data: function () {
return projectDocs.findOne(this.params._id);
},
unload: function() {
var project = projectDocs.findOne(this.params._id);
// need to increment views value by one
projectDocs.update(project._id,
{$inc: {views: 1}}
);
}
// could possibly use layout: popup_layout? here
});
Would love some confirmation that this is actually where I should be doing this (and it does seem a bit inefficient to be doing so many "findOne"'s) but its working for the moment.

Generating Javascript from coffeescript equivalent to manual javascript in _.each underscore

I have a code in Javascript as :
_.each(this.collection.models, function (student) {
$(this.el).append(new StudCloneItemView({ model: student }).el);
}, this);
While I am writing This in coffescript as
_.each this.collection.models , (student) =>
$(#el).append new Item ({ model:student }).el
which generates
_.each(this.collection.models, function(student) {
return $(_this.el).append(new Item({
model: student
}.el));
});
Which isn't desirable as per my requirement . The last segment of "this" element has been missing into the generated javascript . Its very important.
How would I generate The javascript as mentioned on top using the coffeescript I mentioned for _.each ????
Is there anyway to do that ?? Or am I missing any syntax ?
Your JavaScript:
_.each(this.collection.models, function (student) {
$(this.el).append(new StudCloneItemView({ model: student }).el);
}, this);
and what your => CoffeeScript produces:
var _this = this; // This is somewhere above your _.each in the generated JS
_.each(this.collection.models, function(student) {
return $(_this.el).append(new Item({
model: student
}.el));
});
are functionally equivalent. You don't need the context argument to _.each since the => generates an alias for this (called _this) that is used inside the callback.
As an aside, Backbone collections have various Underscore methods mixed in so you don't have to say _.each(#collection.models, ...), you can use each directly on the collection:
#collection.each (student) =>
#$el.append(new StudCloneItemView(model: student).el)
I've also switched to the pre-built $el that your view already has, there's no need to build a new jQuery object on each iteration.
like this:
_.each #collection.models, ((student) ->
$(#el).append new StudCloneItemView(model: student).el
), this