Modifying autocomplete or copying vuetify style? - vue.js

so I'm pretty new to Vue.js and I wanted to modify the autocomplete component (basically make it give suggestions in the specific way that I want it to), which extends the select component. I was thinking to either make my own select component that uses the same style as the veautify select component, OR modifying the veautify autocomplete component to have my desired behavior. Is there a way to do either of these?

You don't need to do either. You can use the filter property to determine the algorithm you want to use to return results:
The filtering algorithm used when searching. example
That lets you control how to search.
You can also control what is supplied back to the list by modifying the collection that is used for the :items property:
get items() {
if (this.red && this.blue && this.shoe.hasOne() {
return myCoolCollection.filter((item) => item.red && item.blue && item.shoe.count() === this.shoe.hasOne()
}
return myCoolCollection
}

Related

Vue.js table updating component data without re-rendering whole component on selected filters

I have a single page dashboard application. I've been playing around with setInterval which works quite well for just updating the data without reloading the page. I put the setInterval function within mounted(), not sure if it best belongs there but works okay.
However! This SPA has a ton of filters. You can search, you can select dropdowns, you can sort, on and on. Say the initial page load has 1000 rows and you use the search bar to narrow it down to one row/one result. Now setInterval runs and it will re render all 1000 rows. This is the method (defined in methods: {} section that initially loads the data and the method used in mounted() with setInterval):
getData: function (arg1, arg2) {
API.getSomeData(arg1, arg2).then(resp => {
getTicketData(resp.data);
this.$data.loading = false;
});
}
Is there a way to account for the filters when it comes to the setInterval piece?
Any and all insight is appreciated.
It sounds like you might be overwriting the same data property when you fetch data from the API and when you filter on it. If that's the case, you should use a computed property to display the filtered records to the user instead.
computed: {
tableRows() {
if (this.filters)
return this.filter()
return this.apiData
}
Where this.filter() will filter down this.apiData without overwriting its contents. Then you can iterate over tableRows in your template (e.g. v-for="row in tableRows") to display those to the user.
If you want to remove some of this logic from your Vue component, you might consider using a Vuex store to both fetch/update from your API and also to calculate the filters.
this.$store.dispatch('fetch_on_interval', { interval: 1000 })
this.$store.dispatch('set_filters', { ...filters })
this.$store.getters('table_data')
Your getter would check the filters and return whatever is relevant. Vuex getters can be used in computed properties too.

Quasar: Is there any way to get the value typed into a QSelect with use-input before it gets removed on blur?

Per the docs you can add the attribute use-input to a QSelect component to introduce filtering and things of that nature: https://quasar.dev/vue-components/select#Native-attributes-with-use-input.
However, if you type something into one of these fields and click outside of it, the text gets removed.
Is there any way to grab that text in Vue before it gets removed and do something with it?
Since v1.9.9 there is also a #input-value event described in the q-select api.
As the api says it's emitted when the value in the text input changes. The new value is passed as parameter.
In the examples there's a filter function, so there you can save it in a data variable:
methods: {
filterFn (val, update, abort) {
update(() => {
this.myDataVariable = val;
})
}
}

When item added, DetailsList doesn't update

I'm using office-ui-fabric-react library. Current version that I'm on is 7.17.0.
My list is super simple:
<DetailsList
columns={this.state.columns}
items={this.state.items}
compact={true}
selectionMode={SelectionMode.none}
enableUpdateAnimations={true}
/>
When I change the items in a separate method (marked async) and do this.setState({items: someNewItems}), the list doesn't get re-rendered. I'm curious is this a known issue, or is the DetailsList needs to be handled in a special way?
To clarify, after executing this.setState nothing changes, but if I resize the page, the new elements appear suddenly.
This is due to shallow comparison, in fact the solution is listed in the documentation here: https://developer.microsoft.com/en-us/fabric#/controls/web/detailslist
From the docs:
My List is not re-rendering when I mutate its items! What should I do?
To determine if the List within DetailsList should re-render its
contents, the component performs a referential equality check within
its shouldComponentUpdate method. This is done to minimize the
performance overhead associating with re-rendering the virtualized
List pages, as recommended by the React documentation.
As a result of this implementation, the inner List will not determine
it should re-render if the array values are mutated. To avoid this
problem, we recommend re-creating the items array backing the
DetailsList by using a method such as Array.prototype.concat or
ES6 spread syntax shown below:
public appendItems(): void {
const { items } = this.state;
this.setState({
items: [...items, ...['Foo', 'Bar']]
})
}
public render(): JSX.Element {
const { items } = this.state;
return <DetailsList items={items} />;
}
By re-creating the items array without mutating the values, the inner
List will correctly determine its contents have changed and that it
should re-render the new values.
There is no issue with DetailsList. The table should update properly, as you indicated that when you resize the page the items show up but before that it doesn't. It's definitely because the render function isn't being called again.
Which means that when you do this.setState you are not updating the states of your present component. As Mirage, in the comments suggested try checking if you have the correct this and you are updating the correct component.

Aurelia force dirty checking without getter

I'm trying to conditionally add a class to an element based on the result of a function call, but Aurelia won't re-run the function when its parameters change. Normally I'd use a getter to force dirty checking but since my function needs arguments that isn't possible.
The function in question looks like this:
isVisible (item, filters) {
// If there are no filters selected, or at least one of the item's tag names are inside the filters the item is considered visible
return (!filters.length || (filters.length && item.tags.some(tag => {
return filters.indexOf(tag.name) !== -1 ? true : false;
})));
}
And in case it's not obvious it takes an item and an array of strings (filters) and then checks if any of item.tags[].name is inside the array of filters.
It is used in my view like so:
<item repeat.for="item of items" item.bind="item" class="${isVisible(item, filters) ? 'show' : 'hide'}"></item>
I also tried just adding the code directly to the view which I assume will force Aurelia to re-calculate things but when adding the entirety of the function's code to the view (inside a ${code here}) I get parse error unexpected >.
Your above example is enough to have it re-evaluated whenever filters changed. However, if you mutate filters, Aurelia won't be able to pick up the change as array observation is not automatic for performance reason. You can work around this by using immutable instances of filters or additionally observe filters length like the following:
<item repeat.for="item of items"
item.bind="item"
class="${isVisible(item, filters, filters.length) ? 'show' : 'hide'></item>

How to implement a switcher/viewstack component with slot?

I'm trying to implement a 'switcher' or 'viewstack' component in Aurelia, this would be useful for wizards, paged content, and stepping through a list of tasks. This would show a single child component at a time from a number of possible children. I'd like the usage markup to resemble:
<my-switcher>
<one-component></one-component>
<two-component></two-component>
<three-component></three-component>
</my-switcher>
Now, the obvious alternatives here are:
<compose view-model.bind="currentStep"> and point the currentStep variable to each component at a time.
(+ves: components are only instantiated when accessed, -ves: needing to know the path for each component, all children need to be valid view-models)
Add an if.bind='active' within the definition of each component in the slot, and just set this active member from the my-switcher class. (+ves: easier to follow, -ves: components need to be specifically written for use here).
Retrieve the children via #children (if this now works reliably?) and add the Element as a child DOM element manually, then call ViewCompiler.enhance. (-ves: can't seem to get get #children to work, larger amount of custom code)
Each of these feels a bit contrived a solution. Does anyone have any idea about whether there a cleaner approach that could/should be used instead?
Combine options 2 and 3 while avoiding the negatives (not sure why you can't get #children to work).
consumer.html
<my-switcher>
<my-switcher-item>
<one-component></one-component>
</my-switcher-item>
<my-switcher-item>
<two-component></two-component>
</my-switcher-item>
<my-switcher-item>
<three-component></three-component>
</my-switcher-item>
</my-switcher>
my-switcher-item.js
export class MySwitcherItem {
constructor() {
this.isActive = false;
}
}
my-switcher-item.html
<template show.bind="isActive">
<slot></slot>
</template>
my-switcher.js
import {children} from 'aurelia-framework';
export class MySwitcher {
#children('my-switcher-item') items = [];
// Here you have access to this.items[index].isActive.
// You can set this value to true or false from this class
// and make sure only one item's isActive is true.
// You could add next() and previous() methods to move between
// the items, etc.
}