How to search through multiple items in Ionic 4? - ionic4

I have a list of cards that displays multiple Tasks.
html
<ion-toolbar>
<ion-searchbar [(ngModel)]="searchTerm" (ionChange)="setFilteredItems()" showCancelButton="focus"></ion-searchbar>
</ion-toolbar>
<ion-card *ngFor="let data of list let i = index">
<ion-card-header>
<ion-card-title class = "linkCenter">{{data.Task}}</ion-card-title>
</ion-card-header>
<ion-card-content>
<p>Status: <span style="color:#222428;" >{{data.StatusName}}</span></p>
<p>Date: <span style="color:#222428;" >{{data.Date}}</span></p>
<p>Auditors: <span style="color:#222428;" ><br><b>{{data.Auditors}}</b></span></p>
</ion-card-content>
</ion-card>
I presently have search bar that searches through the data.Task with the code below
.ts
setFilteredItems() {
this.list = this.filterItems(this.searchTerm);
}
filterItems(searchTerm: { toLowerCase: () => void; }) {
return this.searchable.filter((item: { Task: { toLowerCase: () => { indexOf: (arg0: any) => number; }; }; }) => {
return item.Task.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1;
});
}
What i would like to have is the ability the also search through
data.StatusName, data.Date, data.Auditors, data.Task at the same time.
Is this possible as all post and tutorials seem to only go through searching one item.

Let's focus on the search algorithm part.
My approach would be to:
Cast all searchables to strings
Remove empty space or regular characters
Concatenate all searchables to form 1 long string to represent that item for searching "hayStack"
Change case of needle and hayStack to lowercase
Search for needle in hayStack
We can then search through your searchables with the following.
setFilteredItems() {
this.list = this.filterItems(this.searchTerm);
}
filterItems(needle: string) {
return this.searchable.filter(item => {
// assuming all these data are string type
const hayStack: string = (item.Task + item.StatusName + item.Date + item.Auditors).split(' ').join('').toLowerCase();
needle = needle.split(' ').join('').toLowerCase();
return hayStack.includes(needle);
});
}

Related

how to add a condition like a greater than equal to in filter search in vue js

Hi every one i am going to build a real-estate application
i want to add a condition in Bedrooms filter function like a "greater than equal "
Eg:- if i select 2 on Bedroom list i want to filter greater than equal 2 Bedrooms properties
How can i do this
export default {
data() {
return {
blogs: [],
minbed: this.$route.params.bed,
}
},
created() {
this.$http.get("https://test.json").then(function(data) {
console.log(data);
this.blogs = data.body;
});
},
computed: {
filteredList() {
const { blogs, search, UnitType } = this;
return this.blogs
.filter(blog => blog.Bedrooms.includes(this.minbed))
}
}
<select
v-model="minbed"
id="formInput202"
class="form-control"
value="MaxBedrooms"
>
<option>Max.Bedrooms</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>ST</option>
</select>
includes method is not working in this case. Only accepts string as the param (Ref-Link1).
The inline callback function will sort out this case,
Check the below code.
filteredList() {
const { blogs, search, UnitType } = this;
var MaxBedroomsVal = this.minbed;
return this.blogs.filter( function (blog) {
return blog.Bedrooms >= MaxBedroomsVal;
})
}
Ref: Link2

vuejs add filter to paginated list generated by json response

I´ve just started with Vue and stuck with a basic question. Following this tutorial I´m receiving posts as json. The list of post gets paginated
displayedPosts() calculates and returns shown posts per page
methods: {
...
paginate (posts) {
let page = this.page;
let perPage = this.perPage;
let from = (page * perPage) - perPage;
let to = (page * perPage);
return posts.slice(from, to);
},
...
computed: {
displayedPosts () {
return this.paginate(this.posts);
},
...
Then Template is bound to displayedPosts:
<div class="col-md-4" v-for="post in displayedPosts">
<div class="card mb-4 box-shadow post-cards">
...
Now I´d like to add an input to filter the whole list.
// template input
<input type="search" placeholder="Search..." autofocus v-model="search">
// method to filter model
computed: {
...
filteredItems () {
return this.posts.filter(item => {
return item.title.toLowerCase().indexOf(this.search.toLowerCase()) > -1
})
}
In summary, the pagination does only allow a certain amount of items per page. The filter should hide all list items and only show posts which contain given string.
In case my filter method is correct how would I bind filteredItems to the template for loop as this is already bound to displayesPosts()?
Thanks a lot for your help!
You can change displayedPosts:
computed: {
displayedPosts () {
return this.paginate(this.filteredItems);
},
filteredItems () {
return this.posts.filter(item => {
return item.title.toLowerCase().indexOf(this.search.toLowerCase()) > -1
})
}
}

How do i get property of an object instead of whole object on v-model in vue.js

I had created an input form using html and given v-model="upCountryName", which is an empty array by default but if once name value clicked I had written function to fetch the data from django db using djangorestframework and I had got the data also but in input from v-model="upCountryName" I am getting data as [object Object].
So I written v-model="upCountryName.country" which actually I want to update but input form showing empty, how can I get country name instead of whole object.
----------
HTML --
<td v-on:click="up_country_form(c.id)">
<!--c.id is country.id i am getting from django db and passing it to the method up_country_form(id) in script-->
<center>
<p class="fas fa-pencil-alt"></p>
</center>
</td>
<input type="text" v-model='upCountryName.country' class="form-control">
----------
Vue.js
<script>
export default {
data () {
return {
upCountryName: []
};
},
methods: {
up_country_form (id) {
this.up_country_box = true;
this.$http.get('http://127.0.0.1:8000/getCountry/'+id)
.then((response) => {
this.upCountryName = response.data;
this.loading = false;
});
console.log(id);
this.add_country_box = false;
}
}
};
</script>
You have to make sure response.data is in form like { country: "Some Country Name" } then everything should work fine.
You can see the demo here.
Note: if you use upCountryName.country, the type of upCountryName should be Object not Array.
data () {
return {
upCountryName: {}
}
}

Vue.js 2: Highlight string occurrence

Is there a convenient way to highlight all string occurrences of a string in a text or an element?
Something like the filter method from vue.js 1?
The only problem with my solution is, that the whole v-html-text is now lowercase..
I defined the highlight-method in the methods-block:
methods: {
highlight(words, query) {
if(query === '') { return words }
if(typeof(words) === 'number') {
words = '' + words + ''
}
// when removing the .toLowerCase() your search becomes case-sensitive
return words.toLowerCase().replace(query, '<span style="background: yellow;">' + query + '</span>')
}
}
In my template it looks like this:
<span v-html="highlight('This is some sort of test', 'some')"> // should now highlight 'some'
There are filters in vuejs2 as well. You just create your own method to highlight.
<div>{{ 'some-text' | highlight }}
new Vue({
// ...
filters: {
highlight: function (value) {
// logic
}
}
})

KnockoutJS: Access index of item in array from within the JavaScript template

I populate a list from an array using KnockoutJS:
<div data-bind:"foreach: list">
<input type="text" data-bind="value: myText" />
</div>
function ViewModel() {
self.list = ko.observableArray([
new listItem("sample text")
]);
};
function listItem (text) {
this.myText = text;
};
I can assign an id to the individual instances of my input like so
<input data-bind="attr: { id: $index } ...
How do I access this index from within my listItem function? I want to be able to do something like
function listItem (text) {
this.myText = text;
this.index = $index;
};
in order to use this for further processing.
You could create a custom binding that sets your property to the index, it would look something like:
ko.bindingHandlers.setIndex = {
init: function(element, valueAccessor, allBindings, data, context) {
var prop = valueAccessor();
data[prop] = context.$index;
}
};
This assumes that you are dealing with objects in your array. You would use it like:
<ul data-bind="foreach: items">
<li data-bind="setIndex: 'myIndex', text: name"></li>
</ul>
So, this copies the $index observable on to your object with the property name that you specify. Sample: http://jsfiddle.net/rniemeyer/zGmcg/
Another way that you can do this outside of bindings (this is how I used to do it before $index) is to subscribe to changes to the observableArray and repopulate an index each time.
Here is what an extension to an observableArray might look like:
//track an index on items in an observableArray
ko.observableArray.fn.indexed = function(prop) {
prop = prop || 'index';
//whenever the array changes, make one loop to update the index on each
this.subscribe(function(newValue) {
if (newValue) {
var item;
for (var i = 0, j = newValue.length; i < j; i++) {
item = newValue[i];
if (!ko.isObservable(item[prop])) {
item[prop] = ko.observable();
}
item[prop](i);
}
}
});
//initialize the index
this.valueHasMutated();
return this;
};
You would then use it like:
this.myItems = ko.observableArray().indexed('myIndexProp');
Here is a sample: http://jsfiddle.net/rniemeyer/bQD2C/