Dynamic Route Params from Form Submit - dynamic

I have a form that is passing a string to a search page that uses that string to query an API and display results. When I submit the form, the URL is x/search/string?slug=string. I am looking for a way to keep the URL cleaner and have it be x/search/string.
My form code:
<script lang="ts">
let slug = '';
</script>
<form action={`search/${slug}`}>
<input bind:value={slug} name="slug" type="text" />
<button type="submit" />
</form>
My +page.server.ts code:
export const load: PageServerLoad = async ({fetch, params}) =>{
const fetchSearchResults = async (slug:string) => {
const res = await fetch(`https://openlibrary.org/search.json?q=${slug}`)
const data = await res.json();
return {data};
}
return {
results: fetchSearchResults(params.slug)
}
}
The URL x/search/string?slug=string provides the same results as x/search/string but I am positive I am doing something wrong. Any help or links to some examples that would help would be greatly appreciated.

The input in the form is sent as part of the form request, for GET that results in query parameters.
There are multiple options, e.g. remove the name attribute.
You could also move the element out of the form, but I would not recommend that, as it breaks things like being able to press Enter to submit the form.

Related

Unable to check hidden custom checkbox

I have tried many options, but not successful so far to click on checkbox that are custom checkboxes with :before tag and are hidden. Can someone show me the way to resolve this issue. I tried X-Path and other selector, it finds and clicks on those checkboxes but those checkboxes don't get checked for some reason.
<fieldset class="checkbox">
<legend>Services</legend>
<ul class="multiColumnList">
<li><label for="AccountUsers_0__ViewOrders"><input data-val="true" data-val-required="The View Orders field is required." id="AccountUsers_0__ViewOrders" name="AccountUsers[0].ViewOrders" type="checkbox" value="true" class="hidden-field"><span class="custom checkbox"></span><input name="AccountUsers[0].ViewOrders" type="hidden" value="false">View Orders</label></li>
Here is the screenshot of HTML
Try to click on the checkbox in the following way:
const checkboxSelector = Selector('#AccountUsers_0__ViewOrders');
const labelSelector = Selector('[for="AccountUsers_0__ViewOrders"]')
await t.click(labelSelector);
await t.expect(checkboxSelector.checked).ok();
If this does not help, let me know. I will find a suitable solution for you.
async Check() {
const checkboxSelector = Selector(`[id="AccountUsers_0__ViewOrders"]`)
.with({visibilityCheck: true});
if(!checkboxSelector.checked){
await t.click(checkboxSelector);
}
await t.expect(checkboxSelector.checked).eql(true, 'Should be checked')
}
async UnCheck() {
const checkboxSelector = Selector(`[id="AccountUsers_0__ViewOrders"]`)
.with({visibilityCheck: true});
if(checkboxSelector.checked){
await t.click(checkboxSelector);
}
await t.expect(checkboxSelector.checked).eql(false, 'Should be unchecked')
}
Please try this code and let me know

Svelteki api fetch pages

In short, I want to fetch data from diferents pages from one API I've made.
The API is https://joao-back-ecommerce-prod.herokuapp.com/store/ and as you can see I've multiples endpoints.
With svelte i'm trying to go from page to page in one click with increment function.
exemple:
<script context="module">
export async function load({ fetch, page }) {
const id = page.params.id;
const res = await fetch(
`https://joao-back-ecommerce-prod.herokuapp.com/store/products/?page=${id}`
);
const products = await res.json();
console.log(products);
if (res.ok) {
return {
props: {
products: products.results
}
};
}
return {
status: res.status,
error: new Error('Could not fetch the results')
};
}
</script>
<script>
export let products;
export let id = 1;
const next = () => {
id++;
};
</script>
<ul>
{#each products as product}
<li>
{product.title} - {product.description}
<a href={product.id}>hlmlll</a>
</li>
{/each}
<button on:click={next}>Next</button>
</ul>
I want to go to next page when click on button next. I thought that with increment id + 1 it will be work, but, it doesn't.
In the browser when I change the page number it works.
Any help?
You are just changing a local variable, it does not affect the url.
What you would do is navigate to the next page by changing the url.
There are two ways to do this:
import { goto } from '$app/navigation';
const next = () => goto(`/product/${id+1}`); // change to get correct path for you
or, a better way is to actually just link to the next page instead:
Next
The second option is preferred because you are in fact navigating for which you should use a link (buttons are for actions), it will also work if the user has javascript disabled.
SvelteKit will not actually go to the server and load a new page, it will just fetch the data from the load function and update accordingly, the user will not notice they are on a different page, only the url changes.

handle errors with HTMX

<form
class="" id="form" hx-post="/add/" hx-swap="afterbegin" hx-target="#big_list" hx-trigger="submit">
<input type="text" name="langue1" >
<input type="text" name="langue2">
<div id="errors"></div>
<button type="submit">GO</button>
</form>
<div id="big_list">
.....
</div>
I have a big list in #big_list, and I want my #form appends only one row when submitted.
How with htmx, can I handle errors and show message in #errors ?
I created this solution so you can use hx-target-error = to define which HTML will be displayed after a failed request
document.body.addEventListener('htmx:afterRequest', function (evt) {
const targetError = evt.target.attributes.getNamedItem('hx-target-error')
if (evt.detail.failed && targetError) {
document.getElementById(targetError.value).style.display = "inline";
}
});
document.body.addEventListener('htmx:beforeRequest', function (evt) {
const targetError = evt.target.attributes.getNamedItem('hx-target-error')
if (targetError) {
document.getElementById(targetError.value).style.display = "none";
}
});
If your code raises the errors (validation?), you can change target and swap behavior with response headers.
Response.Headers.Add("HX-Retarget", "#errors");
Response.Headers.Add("HX-Reswap", "innerHTML");
If you want to return a status other than 200, you have to tell htmx to accept it.
4xx would normally not do a swap in htmx. In case of validation errors you could use 422.
document.body.addEventListener('htmx:beforeOnLoad', function (evt) {
if (evt.detail.xhr.status === 422) {
evt.detail.shouldSwap = true;
evt.detail.isError = false;
}
});
It works in htmx 1.8.
If you want to remove the error message on then next sucessfull request, you could use hx-swap-oob. Out of band elements must be in the top level of the response.
So the response could look like this:
<div>
your new row data...
</div>
<div id="errors" hx-swap-oob="true"></div>
Update
You can now use the new powerful extension multi-swap to swap multiple elements arbitrarily placed and nested in the DOM tree.
See https://htmx.org/extensions/multi-swap/
Although it doesn't follow REST principles, you might consider using an swap-oob to report your error back to your user. For example, your request might return a (slightly misleading) status 200, but include content like this:
<div id="errors" hx-swap-oob="true">
There was an error processing your request...
</div>
If it's important to follow REST more precisely, then you'll want to listen to the htmx:responseError event, as mentioned by #guettli in his previous answer.

In Vue, how to get the content of a textarea?

I want to keep the value of a variable identical with the content of a textarea.
I don't want to use v-bind or v-model, because I have already bound the textarea with another value.
This is a notebook app, and the textarea is used to display the content of a note, so it has been bound using v-bind with a note object, like
<textarea cols="30" rows="3" v-bind:value="note"></textarea>
Now, I want to add the "edit note" functionality. So when the content of the textarea changes, I want to store its value into a variable, and when the "submit" button is clicked, I pass the value of the variable, which contains the new content of the note, to backend to update the note.
My question is, how to store the textarea's content into the variable after each time the content changes?
I think I cannot use v-model because this way the note will be changed right after the content of the textarea is modified (though not sent to backend), but this is not what I want. What I want is the note to be changed only after the "submit" button is clicked. Thus, I cannot use v-model
Should I use v-on:change? If so, how to get the content of the textarea?
Like,
<textarea v-on:change="updateTheVariable(I need to get the content of the textarea here)"> ... </textarea>
methods: {
updateTheVariable(content of the textarea) {
this.variable = content of the textarea
}
}
Thanks
I'm assuming this thing only shows up when you click some kind of edit button which is why you don't want to alter note so try something like this instead
<button type="button" v-if="!editMode" #click="editNote">Edit</button>
<form v-if="editMode" #submit="handleSubmit">
<fieldset :disabled="saving">
<textarea v-model="editingNote"></textarea>
<button type="submit">Edit</button>
</fieldset>
</form>
export default {
data: () => ({
note: 'whatever', // maybe it's a prop, maybe assigned later, doesn't matter
editMode: false,
editingNote: null, // this will be used to bind the edited value
saving: false
}),
methods: {
editNote () {
this.editingNote = this.note
this.editMode = true
this.saving = false
},
async handleSubmit () {
this.saving = true // disables form inputs and buttons
await axios.post('/notes/update', { note: this.editingNote}) // just an example
this.note = this.editingNote // or maybe use data from the response ¯\_(ツ)_/¯
// or if it's a prop, this.$emit('updated', this.editingNote)
this.editMode = false
}
}
}
As #Phil indicated in a deleted post, the right way to do it is
<textarea #input="updateTheVariable($event.target.value)"></textarea>
.
.
.
methods:{
updateTheVariable(value){
this.variable = value
}
}

Render form after method completion in VueJS

I am facing a problem with my page with VueJS. It's a page for different translations of the website. It has a dropdown on the top for the language selection that once switched will update the fields with the current language.
The problem starts when it loads, because my form is like this:
<form id="trForm">
...
<input type="text" name="header_title" class="form-control" v-model="translations.header.header_title" />
...
</form>
It's trying to access these attributes before the method returns any data, but somehow it will still show the data once it is complete, but it becomes troublesome when I try to switch the language, it won't because of this problem and also, if I do the following:
<form id="trForm">
...
<input type="text" name="header_title" v-if="translations.header" class="form-control" v-model="translations.header.header_title" />
...
</form>
on each field, those that aren't populated will display no field at all for a new input value. I tried something like translations.features || '', but no success.
I also tried to put on the parent block a condition that if the loading is false will display the form, but since the page is loaded first than the method is executed, it will always be false for the first microsecond.
methods: {
fetchTranslations(e) {
let vm = this;
vm.loaded = false;
$.get('/ajax/admin/translations', { 'locale': e }).done((data) => {
if (data.success) {
vm.translations = JSON.parse(data.translations.translation);
vm.loaded = true;
} else {
toastr.error('Something went wrong');
}
});
},
Please, what do I do? It'd be good to show the form after there is data.
Introduce a new variable, e.g. loaded that defaults to false
Use this variable as a v-if condition on the form
In the callback of your data fetch, set loaded to true.