Nuxt3: Why are selected radio buttons not shown when using in a layout component? - vue.js

I am using custom page layouts for my nuxt3 app. When user selects a radio option, the URL changes to reflect the change (ie, 'solved', 'unsolved' radio options). This works good, however, the radio buttons are not shown for the checked item. For example, when user presses "solved tickets" radio option, the radio button is not shown for that item. What am I doing wrong?
components/AppFilter.vue
<template>
<section>
<div class="list-group">
<NuxtLink to="/" class="list-group-item list-group-item-action">
<input
class="form-check-input me-1"
type="radio"
name="listGroupRadio"
value="all"
id="firstRadio"
/>
<label class="form-check-label" for="firstRadio"
>All tickets/index page</label
>
</NuxtLink>
<NuxtLink to="/solved" class="list-group-item list-group-item-action">
<input
class="form-check-input me-1"
type="radio"
name="listGroupRadio"
value="solved"
id="secondRadio"
/>
<label class="form-check-label" for="secondRadio">Solved Tickets</label>
</NuxtLink>
<NuxtLink to="/unsolved" class="list-group-item list-group-item-action">
<input
class="form-check-input me-1"
type="radio"
name="listGroupRadio"
value="unsolved"
id="thirdRadio"
/>
<label class="form-check-label" for="thirdRadio"
>Unsolved Tickets</label
>
</NuxtLink>
</div>
{{ picked }}
</section>
</template>
Stackblitz reproduction: https://stackblitz.com/edit/nuxt-starter-dmx5zu?file=components/AppFilter.vue

Pretty funky structure IMO but that one works fine
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const picked = ref([])
const updateRadioAndMove = ({ radio, newPath }) => {
picked.value = radio.target.value
router.push(newPath)
}
</script>
<template>
<section>
<br/>
picked radio button >> {{ picked }}
<br/>
<br/>
<div class="list-group">
<input
#change="updateRadioAndMove({ radio: $event, newPath: '/' })"
class="form-check-input me-1"
type="radio"
name="listGroupRadio"
value="all"
id="firstRadio"
/>
<label class="form-check-label" for="firstRadio"
>All tickets/index page</label
>
<input
#change="updateRadioAndMove({ radio: $event, newPath: '/solved' })"
class="form-check-input me-1"
type="radio"
name="listGroupRadio"
value="solved"
id="secondRadio"
/>
<label class="form-check-label" for="secondRadio">Solved Tickets</label>
<input
#change="updateRadioAndMove({ radio: $event, newPath: 'unsolved' })"
class="form-check-input me-1"
type="radio"
name="listGroupRadio"
value="unsolved"
id="thirdRadio"
/>
<label class="form-check-label" for="thirdRadio"
>Unsolved Tickets</label
>
</div>
</section>
</template>

Related

Vue 3 slot props not reactively changing data in parent

I have a slot containing radio buttons in a parent Vue3 component, I'm passing a v-model attribute to these radio buttons and the data model exists in the parent component. However when I change the selected radio button in the slot, the data in the parent component doesn't change.
parent template:
<template>
<div class="card">
<div class="card-body">
<slot
:type="type"
/>
</div>
</div>
</template>
parent vue:
<script>
export default {
data() {
return {
type: 'standard',
}
},
}
</script>
slot content:
<parent v-slot="slotProps">
<div class="row">
<label>
<span class="required">Type</span>
</label>
<label>
Standard Model
<input v-model="slotProps.type" type="radio" name="type" value="standard" required/>
</label>
<label>
Touch Model
<input v-model="slotProps.type" type="radio" name="type" value="touch" required/>
</label>
<label>
Display Model
<input v-model="slotProps.type" type="radio" name="type" value="display" required/>
</label>
</div>
</parent>
I do not think this is a good idea and this is also not recommended by the Vue team.
Anyway, if you really need to do it, as stated by posva from the Vue team, you can pass a method instead to change the value or you can pass an object and modify a property (keep in mind this is not recommended).Here is the object way to do it:
Parent:
<template>
<div class="card">
<div class="card-body">
<slot :myObject="myObject" />
</div>
</div>
</template>
<script>
export default {
data() {
return {
myObject: {
type: "standard",
},
};
},
};
</script>
Slot content:
<parent v-slot="slotProps">
<div class="row">
<label>
<span class="required">Type</span>
</label>
<label>
Standard Model
<input
v-model="slotProps.myObject.type"
type="radio"
name="type"
value="standard"
required
/>
</label>
<label>
Touch Model
<input
v-model="slotProps.myObject.type"
type="radio"
name="type"
value="touch"
required
/>
</label>
<label>
Display Model
<input
v-model="slotProps.myObject.type"
type="radio"
name="type"
value="display"
required
/>
</label>
</div>
</parent>
Here is the method way to do it:
Parent:
<template>
<div>
<div>
<slot :type="type" :onTypeChange="onTypeChange" />
</div>
</div>
</template>
<script>
export default {
data() {
return {
type: "touch",
};
},
methods: {
onTypeChange(event) {
this.type = event.target.value;
},
},
};
</script>
Slot content:
<parent v-slot="slotProps">
<div class="row">
<label>
<span class="required">Type</span>
</label>
<label>
Standard Model
<input
v-model="slotProps.type"
type="radio"
name="type"
value="standard"
required
#change="slotProps.onTypeChange"
/>
</label>
<label>
Touch Model
<input
v-model="slotProps.type"
type="radio"
name="type"
value="touch"
required
#change="slotProps.onTypeChange"
/>
</label>
<label>
Display Model
<input
v-model="slotProps.type"
type="radio"
name="type"
value="display"
required
#change="slotProps.onTypeChange"
/>
</label>
</div>
</parent>

Enable button when checkboxes are active VueJs

I am trying to find a way to activate a button when both of those checkboxes are checked. I've disabled the button but I can't think of a method of actually triggering the isActive when both of them are checked.
<div class="form-check mb-1">
<input
class="form-check-input"
type="checkbox"
id="age"
checked
/>
<label
class="form-check-label"
for="age"
>By clicking this you agree that you
are at least 18 years old.</label
>
</div>
<div class="form-check mb-4">
<input
class="form-check-input"
type="checkbox"
id="terms"
checked
/>
<label
class="form-check-label"
for="terms"
>By clicking this you agree to our
<router-link to="/terms"
>Terms & Conditions</router-link
>
</label>
</div>
<button
:disabled="isActive"
class="btn btn-outline-light btn-lg px-5 mb-1"
type="submit"
>
Register
</button>
<script>
export default {
data() {
return {
isActive: true,
};
},
};
</script>
You should do something like
First checkbox
<input class="form-check-input" v-model="checkOne" type="checkbox" id="age" checked />
second checkbox
<input class="form-check-input" v-model="checkTwo" type="checkbox" id="age" checked />
button
<button :disabled="!checkOne || !checkTwo" class="btn btn-outline-light btn-lg px-5 mb-1" type="submit" >

Nuxt component variable not updated

I wrote the following code for my navbar:
<template>
<div>
<div v-if="!$auth.loggedIn" data-tip="Login" class="tooltip tooltip-bottom">
<nuxt-link to="/login" class="btn btn-square btn-ghost">
<solid-login-icon class="w-6 h-6" />
</nuxt-link>
</div>
<div v-else class="flex items-stretch">
<a class="pr-2 btn btn-ghost rounded-btn"> Welcome, {{ this.$auth.user.username }}! 👋 </a>
<div data-tip="Logout" class="tooltip tooltip-bottom">
<button class="pr-2 btn btn-square btn-ghost" #click="logout()">
<solid-login-icon class="w-6 h-6" />
</button>
</div>
</div>
</div>
</template>
Which is include in the following login page:
<template>
<div class="h-screen shadow bg-base-200 drawer drawer-mobile">
<input id="my-drawer-2" type="checkbox" class="drawer-toggle" />
<div class="drawer-content">
<NavBar />
<div class="grid grid-cols-1 p-5 md:grid-cols-6">
<div class="col-span-1 md:col-span-2 md:col-start-3">
<div class="bg-white shadow card">
<div class="card-body">
<h2 class="text-left card-title">Login</h2>
<form #submit.prevent="userLogin">
<div class="form-control">
<label class="label">
<span class="label-text">Username</span>
</label>
<input
v-model="login.username"
type="text"
placeholder="Username"
class="input input-bordered"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Username</span>
</label>
<input
v-model="login.password"
type="password"
placeholder="Password"
class="input input-bordered"
/>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary btn-md">Login</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<SideBar />
</div>
</template>
<script>
export default {
data() {
return {
login: {
username: '',
password: '',
},
}
},
methods: {
async userLogin() {
try {
const response = await this.$auth.loginWith('local', { data: this.login })
} catch (err) {}
},
},
}
</script>
Upon loggin in with correct credentials the page keeps dispalying the "Login"-icon instead of the Welcome message.
I've tried to replace !$auth.loggedIn with loggedIn (coming from the data function) and with !this.$auth.loggedIn" but both don't seem to solve the issue

How to listen to events from bootstrap-vue modal?

I have two modals in my page and I need a way to listen to 'ok' event when pressing ok button on first modal and respond by opening the another modal.
There are no examples in the documentation:
https://bootstrap-vue.js.org/docs/components/modal/
I wanted to use this listener but nothing is explained and I couldn't find out what is what here.
export default {
mounted() {
this.$root.$on('bv::modal::show', (bvEvent, modalId) => {
console.log('Modal is about to be shown', bvEvent, modalId)
})
}
}
This is the relevant part of my code:
<div>
<b-modal id="modal-center-add-post" style="width: 120px" centered class="h-50 d-inline-block min-vw-100" ok-title="next" >
<add-post></add-post>
</b-modal>
</div>
<div>
<b-modal id="modal-center-add-content" style="width: 120px"
centered class="h-50 d-inline-block min-vw-100"
ok-only ok-title="Create" >
<add-content></add-content>
</b-modal>
</div>
and add-post component code is
<template>
<form>
<div class="form-group row">
<label for="title"
class="col-sm-2 col-form-label">
Title
</label>
<div class="col-sm-10">
<input type="text"
class="form-control"
id="title"
placeholder="Title">
</div>
</div>
<div class="form-group row">
<label for="chooseTopic"
class="col-sm-2 col-form-label">
Topic
</label>
<div class="col-sm-10">
<select id="chooseTopic" class="form-control">
<option selected>Leadership</option>
<option>HR</option>
<option>Sales</option>
<option>Marketing</option>
</select>
</div>
</div>
<fieldset class="form-group">
<div class="row">
<legend class="col-form-label col-sm-2 pt-0"> Type</legend>
<div class="col-sm-10">
<div class="form-check-inline ">
<label class="form-check-label"
for="video"
:class="{'checked':(isChecked==='video')}"
#click="isChecked='video'">
<input class="form-check-input"
type="radio" name="video"
id="video"
v-model="postingType"
value="video" checked>
<i class="fab fa-youtube "></i>
Video
</label>
</div>
<div class="form-check-inline">
<label class="form-check-label"
for="ebook"
:class="{'checked':(isChecked==='ebook')}"
#click="isChecked='ebook'">
<input class="form-check-input"
type="radio"
name="ebook"
id="ebook"
v-model="postingType"
value="ebook">
<i class="far fa-file-pdf "></i>
Ebook
</label>
</div>
<div class="form-check-inline ">
<label class="form-check-label "
for="article"
:class="{'checked':(isChecked==='article')}"
#click="isChecked='article'">
<input class="form-check-input " type="radio"
name="article" id="article"
v-model="postingType" value="article" >
<i class="fas fa-pen-square "></i>
Article
</label>
</div>
</div>
</div>
</fieldset>
</form>
</template>
<script>
export default {
name: "AddPost",
data(){
return{
postingType:'',
isChecked:'video'
}
},
}
</script>
So when I click on ok (next) in add-post component I want the second modal to pop up.
it's right on the bottom of the documentation under Events
basicly use
#ok="yourOkFn"

Vue.js Bootstrap 4 , cannot check radio button

I am trying to check by default the Mrs radio button... but it does not work ... I also tried to add a checked attribute wo any success //
what could be wrong with my coding ?
<div class="col-lg-9">
<form>
<!-- Full name -->
<div class="input-group input-group-lg mb-3">
<div class="input-group-prepend">
<div class="input-group-text pb-0">
<label class="form-group-label active"><input v-model="gender" type="radio" value="Mrs"> Mrs</label>
</div>
<div class="input-group-text pb-0">
<label><input v-model="gender" type="radio" name="gender" value="Mr"> Mr</label>
</div>
</div>
<input v-model="username" #input="$v.username.$touch" v-bind:class="{ error: $v.username.$error, valid: $v.username.$dirty && !$v.username.$invalid }" type="text" class="form-control" placeholder="Indiquez votre prénom et votre nom">
</div>
</form>
</div>
This is how you might do it. I've added the toggle button to show how this binding works:
new Vue({
el: '#app',
data: {
radio: 'mrs',
},
methods: {
toggle() {
this.radio = this.radio === 'mrs' ? 'mr' : 'mrs';
}
},
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<input v-model="radio" type="radio" value="mrs">
<label>Mrs</label>
<input v-model="radio" type="radio" value="mr">
<label>Mr</label>
<button #click="toggle">Toggle</button>
</div>
EDIT: Snippet fixed and updated
You need have the value for gender set in the data model.
https://www.codeply.com/go/KDKbm4PTBO
<label class="form-group-label active">
<input v-model="gender" type="radio" value="Mrs"> Mrs
</label>