Creating a dynamic search - vue.js

I'm currently using Vuetify to create a datatable, I see with the search as you type it filters down to narrow the results based on what's type in. I'm curious how I can use the same search bar, so when I hit enter it'll actually take the value and rebuild the datatable using the same axios call but adding the params to the URL. I still want to be able to filter current results when typing and not hitting enter though. Is this possible?
Overall Im trying to create tags when searching. Users would have the ability to hit enter, rebuild the table, but see the value they entered as a tag. With also the ability to x out of it and delete to restore defaults.

Assuming you have a search input like this:
<v-text-field
v-model="search"
append-icon="search"
label="Search"
single-line
hide-details
v-on:keyup.enter="myFunction"
></v-text-field>
You can add the v-on:keyup.enter as above, then put your functionality in myFunction
In myFunction, you can say this.search to get the value of that, and you can do whatever you want with it.

Related

Prevent list display filter from resetting v-list selection

Version info: Vuetify 2.6.3, Vue 2.6.14, Nuxt 2.15.8
I'm making a custom component that is supposed to be somewhat similar to v-autocomplete, except that it's rendered as bottom sheet. If user enters a display filter into v-text-field, the option list (v-list) is supposed to display only those options that match the filter.
In overall it works fine except one use case: let say the list has 5 items (aa, bb, cc, dd, ee) and user selected bb and cc from the list. Now, v-list-item-group's model selectedItems contains the 2 selected items bb and cc, perfect! However, when user enters b into display filter, the already selected item cc will be auto deleted from selectedItems. I can't tell if selectedItems change is caused by filter or by user selection. Is there a way to maintain the selection in model?
I'm considering a hack - if an item is selected, keep it in filteredChoices even if it does not match the filter. This behaviour is bearable but UX wise not as intuitive as the filter of v-autocomplete.
The simplified structure looks like the below:
<template>
<v-bottom-sheet scrollable>
<v-card>
<v-card-text>
<v-list>
<v-list-item-group
v-model="selectedItems"
:mandatory="!optional"
:multiple="multiple"
>
<v-list-item
v-for="item in filteredChoices"
:key="item.value"
:value="item"
>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card-text>
<v-text-field
v-model="filterInput"
placeholder="filter choices..."
hide-details
></v-text-field>
</v-card>
</v-bottom-sheet>
</template>
<script>
...
filteredChoices() {
if (this.filterInput == null) {
return this.allItems
}
return this.allItems.filter((item) => {
return item.label
.toLocaleLowerCase()
.includes(String(this.filterInput).toLocaleLowerCase())
})
},
...
</script>
How I reach the solution:
I was quite new to front-end stuff. Previously, when I was learning how to implement v-model support for custom component, all web resources I came across say the same thing - bind inner component's value props to custom component's value props. However I just discovered that this is merely one of the ways rather than a must. With that new learning, more possibilities pop up in my mind and one of them lead me to below solution.
Solution:
Decouple the custom component value from bottomsheet's list
Bind the model of inner v-autocomplete to an array data, say internalValue. (this inner component is not included in question's template for simplification)
Bind the model of inner v-list-item-group (in bottomsheet) to a separate data, say bottomSheetSelections.
Update the custom component value based on user actions in bottomsheet
Add a watcher to bottomSheetSelections array:
if the array grows, it means the user has selected more item. We should push the additional item to internalValue.
if the array shrinks:
if the missing item is still there in filteredChoices, the removal is triggered by user de-selection. We should remove this item from internalValue.
else, we consider the removal is triggered by list filter. No action is needed.
Restore user selection in bottomsheet on clearing filter
Add a watcher for filteredChoices. Whenever the array grows, if the additional choice exist in internalValue, we should push it to bottomSheetSelections.
Summary
Strictly speaking, this doesn't solve the ask of question's title - the list selection in bottomsheet (bound to v-list-item-group) is still getting reset. However, at least we're able to restore it in bottomsheet on clearing filter.
More importantly, this solution achieved the objective mentioned in question details - retain the user selection value. We kept it in a separate data internalValue.
I haven't test this solution with long list of data. My guts feeling is that there could be more efficient solution. Please share it if you have a better solution.

v-select/Vue: How to enter value not in the list?

I'm trying to find a way to add a new value using v-select previously not in the list. So that the new value entered will become the selected option.
This is my current code:
<v-select
ref="systemSelect"
v-model="reservation.system"
name="system"
label="Select System"
:disabled="isBusy"
:options="systems"
#input="getSystems"
/>
In UI the component looks like this. Here I use Vuex only to get :options. Currently if I enter a new value and click outside that value disappears since its not found in the list
Expected: Would like to enter a new value and use this value as current in the form and save it. Is there a way to achieve this?
Any help would be appreciated.
Thanks!
If you're using vue select, you can use the attribute taggable and multiple to push your own options:
<v-select taggable multiple />
See this link:
https://vue-select.org/guide/values.html#tagging

How to populate drop down when it is built using an input tag using java and selenium

I have a drop down built with extJS.
<input id="combo-1786-inputEl" data-ref="inputEl" type="text" size="1" name="Query Category" placeholder="Select query category" role="combobox" aria-hidden="false" aria-disabled="false" aria-readonly="false" aria-invalid="true" aria-required="true" aria-haspopup="true" aria-expanded="false" aria-autocomplete="list" class="x-form-field x-form-required-field x-form-text x-form-text-default x-form-invalid-field x-form-invalid-field-default x-form-empty-field x-form-empty-field-default" autocomplete="off" data-componentid="combo-1786" data-errorqtip="<ul class="x-list-plain"><li>This field is required</li></ul>" aria-describedby="combo-1786-ariaErrorEl">
As we can see the tag used is 'input' and not 'select'.
So when I looked up about how to populate it, most answers were made under the assumption that it was created using a 'select' tag and it did not work.
Also the drop downitems are fetched from DB only when I click on the arrow on the dropdown:
So as a result of this, the drop down items cant be found on the page source.
Can someone one please suggest how to populate such downs using the best practice?
P.S-I do have a workaround, but its not at all good code practice and not at all generic:
driver.findElement(By.xpath("//*[#id='combo-1731-trigger-picker']")).click();//clicking on the arrow key of the drop down.
//Once the drop down item comes, I am trying to replicate pressing the keyboard arrow key,by sending down arrow key to the drop down item(web element)
//This works for me because I know the extact position of my drop down item in the drop down item list.It will stop working if the postion of the drop item changes
//so below loop just presses the down arrow key required number of times.
for(int i=0;i<5;i++){
driver.findElement(By.xpath("//*[#id='combo-1731-inputEl']")).sendKeys(Keys.ARROW_DOWN);
}
driver.findElement(By.xpath("//*[#id='combo-1731-inputEl']")).sendKeys(Keys.ENTER);
If you read the comments mentioned along with the above code, then you can understand how fragile the logic is.
Please help.
You are trying to click/ select the item in the drop down correct?
Do the drop down items have unique id's? If so you should be able to just pass it the specific xpath id.
I personally use Css to find elements, in that case it would be
driver.find_element(By.CSS_SELECTOR,'#combo-1731-trigger-picker').click()
driver.find_element(By.CSS_SELECTOR, '#combo-1731-inputEl > nth:child(x)').click()
where x = the count of your drop down item.
or if they have unique id's then use
driver.find_element(By.CSS_SELECTOR, '#theUniqueIdGoesHere').click()
I wrote a whole weeks worth of tests, using xpath selectors, it was painful day to day running the test and watching it fail. Going back and changing everything to Css selectors has saved me many head aches since I started writing Auto tests.
Edit: you could try the following,
driver.findElement(By.linkText("Your Links Text Here")).click();
This will only work if each links text is unique as well, if not it will select the first one it finds.
If these work for you would you mind accepting my answer?

Conditional stepper-content and form content with Vuetify

I am currently using Vue Js with Vuetify and Vuelidate for an SPA.
I have a form to create a new Account, which is pretty standard.
What I have decided to do though is break the form into steps and utilise the v-stepper component from Vuetify.
The part I am stuck on is how the users choices as they fill in the form can dictate the steps. For example;
Using a v-if I determine if the v-text-field is needed to be shown, what I am unsure of is how this will effect the forms data/model that will eventually be sent in a POST.
Am I looking at this in the right way? or can someone suggest a better approach?
Code:
<template>
<v-form v-model="stepCount">
<-stepper-header>
<v-stepper-step step="1" :complete="stepStage > 1">
Account Details
</v-steper-step>
<v-divider></v-divider>
<v-stepper-step step="2" :complete="stepStage > 2">
Personal Details
</v-steper-step>
</v-stepper-header>
<v-stepper-content step="1">
<v-text-field>
Usual filler for a text field {Username}
</v-text-field>
<v-text-field>
Usual filler for a text field {Password}
</v-text-field>
<v-text-field>
Usual filler for a text field {Age}
</v-text-field>
<v-text-field>
label="Gender"
v-model="gender
:error-messages="genderErrors"
#intput="v.gender.$touch()"
#blur="v.gender.$touch()"
</v-text-field>
</v-stepper-content>
<v-stepper-content>
<v-text-field v-if="gender == 'F'">
label="Bra Size"
v-model="braSize
:error-messages="braSizeErrors"
#intput="v.gender.$touch()"
#blur="v.gender.$touch()"
</v-text-field v-else>
<v-text-field>
Usual filler for a text field {t-ShirtSize}
</v-text-field>
</v-stepper-content>
Thanks in advance.
It seems like your asking several things here so here is what I think the answer your looking for is.
To control the stepper flow you can either set the stepStage to variables like steppers shows or use a computed variable that returns the state based on the collected data.
Computed state
computed:{
stepStage(){
if(/*certain content is correctly filled and a next button has been clicked*/)return 1
if(/*check another computed variable that decides if the form is complete*/)return 2
//etc
}
}
As far as v-if statements in forms. It shouldn't affect a submitted form since it actually removes or inserts an element based on the value as stated in the first paragraph of this section. Note v-stepper doesn't use v-if.
For more control you may consider saving the data in the state of the component and then use javascript to do the actual submission. This allows you to have complete control over what is sent to the server.

HTML text input and using the input as a variable in a script(tcl)/sql(sqlite)

I'm very VERY new at this whole web thing. And I'm just very confused in general. Basically, what I want to do is take an input via text using HTML and adding that input to database, table trans. Should be simple but I am lost.
<li>Transaction Number</li>
<li><input type=|text| name=|tnumber| </li> // do i need to use value?
<li>Employee Name</li>
<li><input type=|text| name=|ename| </li>
<li><input type=|SUBMIT| value=|Add|></li>
......
......
sqlite3 db $::env(ROOT)/database.db
db eval {INSERT INTO trans VALUES ($tnumber, $ename)}
db close
They are both in a same file and there are only two fields to the database to keep things simple. What I can see here is that tnumber and ename aren't declared as variables. So how do I do that so that the text input is assigned to respective variables?
You're after the ncgi package (in Tcllib), which you can use to decode the values in the form and extract them into variables. To do this, you'd have a webpage with a form like this:
<form method="POST" action="/cgi-bin/addTransaction.tcl">
<li>Transaction Number: <input type="text" name="tnumber">
<li>Employee Name: <input type="text" name="ename">
<li><input type="submit" value="Add">
</form>
(I'll not go into much more depth with the details of writing a form on a webpage.)
Then, in your program (addTransaction.tcl) you do something like this:
package require ncgi
package require sqlite3
ncgi::parse
set xact [ncgi::value "tnumber"]
set name [ncgi::value "ename"]
sqlite3 db $::env(ROOT)/database.db
db eval {INSERT INTO trans VALUES ($xact, $name)}
db close
Note that I've changed the names of the variables to be different from the ones in the webform. This is to show that they do not need to be the same. A few other things to note are that you can make the transaction number field optional (supply a default via the second optional argument to ncgi::value) and it might also be better to do generation of transaction ids in the database (but that's another separate question; I've focussed in this answer on how to couple from the web into SQLite).
Of more interest is the fact that the above code is free of SQL injection attacks. However, whenever you come to taking the contents of the database and sending it back out to the web, you'll need to be careful again or you'll leave open XSS attacks. That's when the html package (Tcllib again) is useful, since it lets you generate correct hazard-free output with minimal effort. But that's another question...