I would like to translate the titles that are passed to my component via props. However I assume because my strings are being passed via props they are not being translated like the rest of my code. Below you will find my current 2 components that I am working with:
Parent Component:
`<setting-section
:title="$t('Random Text 1')"
:description="$t('Random Text 2')"
>`
In the Child:
`<template>
<div class="flex grid w-full">
<div class="divider mr-4 mt-5" />
<div class="header col-2">
<div class="title text-primary">{{ title }}</div>
<div class="description text-xs">{{ description }}</div>
</div>
<div class="flex col-10" v-if="!isLoading">
<slot />
</div>
<div class="flex col-10" v-else>
<Skeleton height="5rem" />
</div>
</div>
</template>
<script>
export default {
name: 'Menu',
props: {
title: {
type: String,
default: '',
},
description: {
type: String,
default: '',
},
},
};
</script>`
How ever if I do add the below variation it obviously wont work.
`<template>
<div class="flex grid w-full">
<div class="header col-2">
<div class="title text-primary">{{ $t('title')}} </div>
<div class="description text-xs">{{ description }}</div>
</div>
</div>
</template>`
Your both the solutions should work as we always configured VueI18n at global level. Hence, translation literals always accessible from any nested component.
Live Demo as per both the use cases :
Vue.component('child-one', {
props: ['childmsg'],
template: '<p>{{ childmsg }}</p>'
});
Vue.component('child-two', {
template: `<p>{{ $t('message') }}</p>`
});
Vue.use(VueI18n);
const i18n = new VueI18n({
locale: 'ja',
fallbackLocale: 'en',
messages: {
"ja": {
"message": "こんにちは、世界"
},
"en": {
"message": "Hello World"
}
}
});
new Vue({
el: "#app",
i18n,
data() {
return {
locale: "ja"
}
},
watch: {
locale(newLocale) {
this.$i18n.locale = newLocale;
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.8/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue-i18n#8.8.2/dist/vue-i18n.min.js"></script>
<main id="app">
<div>
<label><input type="radio" value="ja" v-model="locale" />Japanese</label>
<label><input type="radio" value="en" v-model="locale" />English</label>
</div>
<h3>Passing translated string from parent</h3>
<child-one :childmsg="$t('message')"></child-one>
<h3>Transaltions happens in child component itself</h3>
<child-two></child-two>
</main>
Related
I've been trying to create a simple component with a styled checkbox and a corresponding label. The values (strings) of all selected checkboxes should be stored in an array. This works well with plain html checkboxes:
<template>
<div>
<div class="mt-6">
<div>
<input type="checkbox" value="EVO" v-model="status" /> <label for="EVO">EVO</label>
</div>
<div>
<input type="checkbox" value="Solist" v-model="status" /> <label for="Solist">Solist</label>
</div>
<div>
<input type="checkbox" value="SPL" v-model="status" /> <label for="SPL">SPL</label>
</div>
</div>
<div class="mt-3">{{status}}</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
let status = ref([]);
</script>
It results in the following, desired situation:
Now if I replace those checkboxes with my custom checkbox component, I can't get it to work. If I check a box, it's emitted value seems to replace the status array instead of it being added to or removed from it, resulting in the following:
So all checkboxes are checked by default for some reason, when I click on one of them they all get unchecked and the status value goes to false and clicking any of the checkboxes again will check them all and make status true.
Now I get that returning whether the box is checked or not in the emit returns a true or false value, but I don't get how Vue does this with native checkboxes and how to implement this behaviour with my component.
Here's the code of my checkbox component:
<template>
<div class="mt-1 relative">
<input
type="checkbox"
:id="id ?? null"
:name="name"
:value="value"
:checked="modelValue ?? false"
class="bg-gray-200 text-gold-500 rounded border-0 w-5 h-5 mr-2 focus:ring-2 focus:ring-gold-500"
#input="updateValue"
/>
{{ label }}
</div>
</template>
<script setup>
const props = defineProps({
id: String,
label: String,
name: String,
value: String,
errors: Object,
modelValue: Boolean,
})
const emit = defineEmits(['update:modelValue'])
const updateValue = function(event) {
emit('update:modelValue', event.target.checked)
}
</script>
And the parent component only uses a different template:
<template>
<div>
<div class="mt-6">
<Checkbox v-model="status" value="EVO" label="EVO" name="status" />
<Checkbox v-model="status" value="Solist" label="Solist" name="status" />
<Checkbox v-model="status" value="SPL" label="SPL" name="status" />
</div>
<div class="mt-3">{{status}}</div>
</div>
</template>
I've tried to look at this answer from StevenSiebert, but it uses an object and I want to replicate the original Vue behaviour with native checkboxes.
I've also referred the official Vue docs on v-model, but can't see why this would work different with native checkboxes than with components.
Your v-model is the same for every checkbox, maybe like following snippet:
const { ref } = Vue
const app = Vue.createApp({
setup() {
const status = ref([{label: 'EVO', status: false}, {label: 'Solist', status: false}, {label: 'SPL', status: false}])
return {
status
}
},
})
app.component('Checkbox', {
template: `
<div class="mt-1 relative">
<input
type="checkbox"
:id="id ?? null"
:name="name"
:value="value"
:checked="modelValue ?? false"
class="bg-gray-200 text-gold-500 rounded border-0 w-5 h-5 mr-2 focus:ring-2 focus:ring-gold-500"
#input="updateValue"
/>
{{ label }}
</div>
`,
props:{
id: String,
label: String,
name: String,
value: String,
errors: Object,
modelValue: Boolean,
},
setup(props, {emit}) {
const updateValue = function(event) {
emit('update:modelValue', event.target.checked)
}
return {
updateValue
}
}
})
app.mount('#demo')
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.18/tailwind.min.css" integrity="sha512-JfKMGsgDXi8aKUrNctVLIZO1k1iMC80jsnMBLHIJk8104g/8WTaoYFNXWxFGV859NY6CMshjktRFklrcWJmt3g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<div id="demo">
<div>
<div class="mt-6" v-for="box in status">
<Checkbox v-model="box.status" :value="box.label" :label="box.label" name="status"></Checkbox>
</div>
<div class="mt-3">{{status}}</div>
</div>
</div>
I can pass an array as the v-model to the Checkbox component and mark is as checked if the value is within that array. When the checkbox gets toggles, I add or remove the value to/from the array depending if it's already in there.
Parent component:
<template>
<div>
<div class="mt-6">
<Checkbox v-for="box in ['EVO', 'Solist', 'SPL']" v-model="status" :value="box" :label="box" name="status" />
</div>
<div class="mt-3">{{status}}</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
let status = ref([]);
</script>
Checkbox component:
<template>
<div class="mt-1 relative">
<input
type="checkbox"
:id="id ?? null"
:name="name"
:value="value"
:checked="modelValue.includes(value)"
class="bg-gray-200 text-gold-500 rounded border-0 w-5 h-5 mr-2 focus:ring-2 focus:ring-gold-500"
#input="updateValue"
/>
{{ label }}
</div>
</template>
<script setup>
const props = defineProps({
id: String,
label: String,
name: String,
value: String,
errors: Object,
modelValue: Boolean,
})
const emit = defineEmits(['update:modelValue'])
const updateValue = function(event) {
const arr = props.modelValue;
if(arr.includes(props.value)) { // Remove if present
arr.splice(arr.indexOf(props.value), 1)
}
else { // Add if not present
arr.push(props.value)
}
emit('update:modelValue', arr)
}
</script>
Or to accomodate for booleans as well (like native checkboxes):
<template>
<!-- ... -->
<input
type="checkbox"
:value="value"
:checked="isChecked"
#input="updateValue"
<!-- ... -->
/>
<!-- ... -->
</template>
<script setup>
// ...
const isChecked = computed(() => {
if(props.modelValue instanceof Array) {
return props.modelValue.includes(props.value)
}
return props.modelValue;
})
const updateValue = function(event) {
let model = props.modelValue;
if(model instanceof Array) {
if(isChecked()) {
model.splice(model.indexOf(props.value), 1)
}
else {
model.push(props.value)
}
}
else {
model = !model
}
emit('update:modelValue', model)
}
Hello I have a request in vue.js where b-input is required, if not it cannot continue, I've tried
required
validation-message="name required"
in b-step-item, also in the watch event.
watch: {
activeStep(step) {
this.ValidationSteps()
},
},
methods: {
ValidationSteps() {
this.erros = []
if (this.nameField === '') {
this.erros.push({ description: 'Field is required' })
}
},
},
but I still can't get the field to continue.
This is my code, then I'll fix how the error messages appear below the field. (if it is possible to give the solution).
I've searched and I can't find the solution in the documentation
<template>
<section>
<b-steps v-model="activeStep" :has-navigation="false">
<b-step-item step="1" label="Account" :clickable="isStepsClickable">
<h1 class="title has-text-centered">Account</h1>
<b-input
v-model="NombreCampo"
placeholder="Enter field name"
required
validation-message="name required"
></b-input>
<article v-if="erros.length > 0" class="message is-danger">
<div class="message-header">
<p>Error ({{ erros.length }})</p>
</div>
<div class="message-body">
<div class="content">
<ul>
<li v-for="(db, index) in erros" :key="index">
{{ db.description }}
</li>
</ul>
</div>
</div>
</article>
</b-step-item>
<b-step-item
step="2"
label="Profile"
:clickable="true"
:type="{ 'is-success': true }"
>
<h1 class="title has-text-centered">Profile</h1>
</b-step-item>
<template #navigation="{ previous, next }">
<b-button
:disabled="previous.disabled"
#click.prevent="previous.action"
>
Previous
</b-button>
<b-button :disabled="next.disabled" #click.prevent="next.action">
Next
</b-button>
</template>
</b-steps>
</section>
</template>
<script>
export default {
data() {
return {
activeStep: 0,
erros: [],
nameField: '',
}
},
watch: {
activeStep(step) {
this.ValidationSteps()
},
},
methods: {
ValidationSteps() {
this.erros = []
if (this.nameField === '') {
this.erros.push({ description: 'Field is required' })
}
},
},
}
</script>
Any suggestion or solution would be appreciated.
I'm completely new to VueJS and am trying to create a project tile list with different data values per tile. I use Vue CLI. I created a component which is my template for one project tile.
component TheProjectTile.vue :
<template>
<router-link to="{{ project.url }}">
<div
class="row project-container"
style="background-color: {{ project.backgroundcolor }};"
v-scrollanimation
>
<div class="column column-60">
<h2>{{ project.title }}</h2>
<div class="button">view</div>
</div>
<div class="column">
<img src="#/assets/img/{{ project.image }}" alt="{{ project.title }}" />
</div>
</div>
</router-link>
</template>
<script type="text/javascript">
export default {
props: { project: Object },
data() {
return {}
}
}
</script>
Then I have my View on my Vue CLI application where I want to render the project tiles and where I want to give the data to the tiles:
View where the projects should be shown
<template>
<div id="projekte">
<section class="container">
<div id="projects">
<projectlist v-for="project in projects" :project="project" />
</div>
</section>
</div>
</template>
<script>
import TheProjectTile from './components/TheProjectTile'
export default {
components: {
projectlist: TheProjectTile
},
data() {
return {
projects: [
{
url: '/projekte/client1',
backgroundcolor: '#005ca9',
title: 'Website client 1',
img: 'client1.png'
},
{
url: '/projekte/client2',
backgroundcolor: '#c10b25',
title: 'Website client 2',
img: 'client2.png'
}
]
}
}
}
</script>
What do I need to change that it works? :/
Please take a look at following snippet:
You need to bind data with v-bind or :,
in v-for loop you need key
Vue.component('projectList', {
template: `
<a :to="project.url">
<div
class="row project-container"
:style="{'background-color': project.backgroundcolor}"
>
<div class="column column-60">
<h2>{{ project.title }}</h2>
<div class="button">view</div>
</div>
<div class="column">
<img :src="'#/assets/img/'+project.image" :alt="project.title" />
</div>
</div>
</a>
`,
props: { project: Object },
})
new Vue({
el: '#demo',
data() {
return {
projects: [{url: '/projekte/client1', backgroundcolor: '#005ca9', title: 'Website client 1', img: 'client1.png'}, {url: '/projekte/client2', backgroundcolor: '#c10b25', title: 'Website client 2', img: 'client2.png'}]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div id="projekte">
<section class="container">
<div id="projects">
<!-- 👇 key -->
<project-list v-for="(project, index) in projects" :key="index" :project="project" />
</div>
</section>
</div>
</div>
I am trying to create a searching component using Vue 3 in cli
i import data from json file and I have tried many functions
but the search filter doesn't work
so i need a search filter function
this is my code
import data from "#/assets/data.json";
export default {
name: "Home",
data: function () {
return {
allData: data,
search: "",
};
},
components: { myComp, foooter, headeer },
computed: {
filter() {
return this.allData.filter((item) =>
item.body.toLowerCase().includes(this.search.toLowerCase())
);
},
},
};
and this is the input and cards that i show in
<div class="row justify-content-md-center">
<div class="col-md-4">
<div class="form-group">
<input
class="form-control"
type="text"
name="search"
placeholder="search..."
v-model="search"
/>
</div>
</div>
</div>
<div class="row">
<my-comp
v-for="item in filter"
:key="item.id"
:id="item.id"
:imgsrc="item.imgsrc"
:price="item.price"
:city="item.city"
:country="item.country"
:reviewnum="item.reviewnum"
:daynum="item.daynum"
/>
</div>
i have a costume made Tabs and Tab from Laracasts Tabs Tutorial , and it work fine, but i need to load data when the tab is changed and i did that but when the data is loaded,
i need to render another component which have accordion and inside each accordion tab their some charts components need to be render also
so how can i render the accordion with the charts components when the Tabs tab is changed
Tabs Component:
<template>
<div class="tab-container -mt-px w-full">
<div class="tabs">
<ul class="list-reset flex border-b">
<li class="" v-for="(tab, index) in tabs" role="tab">
<a class="bg-white inline-block font-semibold hover:no-underline"
:class="[
{
'active-tab-link text-blue-dark border-l border-r active-tab-link-p': tab.isActive,
'text-blue hover:text-blue-darker non-active-tab-link-p': !tab.isActive
},
]"
:href="tab.href" #click="selectedTab(tab)">
{{tab.name}}
</a>
</li>
</ul>
</div>
<div class="tabs-details px-4 w-full">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: "Tabs",
data() {
return {
tabs: []
};
},
created() {
this.tabs = this.$children;
// this.selectFirstTab();
},
methods: {
selectedTab(selectedTab) {
this.$emit('onTabChange', selectedTab);
this.tabs.map((tab, index) => {
tab.isActive = (tab.name === selectedTab.name)
});
},
}
}
</script>
Tab Component:
<template>
<div class="w-full" role="tabpanel" v-show="isActive">
<slot></slot>
</div>
</template>
<script>
import {isEmpty} from "../helpers/Helper";
export default {
name: "Tab",
props: {
name: {
type: String,
required: true
},
selected: {
type: Boolean,
default: false,
},
isFirst: {
type: Boolean,
default: false,
},
},
data() {
return {
// isActive: false,
isActive: true,
// isFirst: this.isFirst
};
},
computed: {
href() {
return this.formatHref(this.name);
},
},
mounted() {
this.selectTabFromURL();
},
methods: {
selectTabFromURL() {
let hash = this.$route.hash;
if (this.selected) {
this.isActive = this.selected;
} else if (!isEmpty(hash)) {
this.isActive = (this.formatHref(this.name) === hash);
} else if (this.isFirst) {
this.isActive = this.isFirst;
} else if (!this.isFirst && this.isActive) {
this.isActive = !this.isActive;
}
},
formatHref(id) {
return `#${id.toLowerCase().replace(/ /g, '-')}`;
}
}
}
</script>
the main component:
<template>
<!--components tabs start-->
<div class="flex flex-col">
<div class="mt-3 border-t-4 border-primary-color border-6 bg-white">
<div class=" border border-gray-400 lg:border-l-0 lg:border-t lg:border-gray-400 rounded-b lg:rounded-b-none lg:rounded-r leading-normal">
<Tabs #onTabChange="handleTabChange">
<!--:name="`${tab.name} - ${tab.component.type}`"-->
<Tab v-for="(tab, index) in page.tabs"
:key="tab.id"
:id="tab.slug"
:name="tab.name"
:slug="tab.slug"
:isFirst="index === 0"
>
<div>
How to render the dynamic accordion with the charts one time only no need to re-render
</div>
</Tab>
</Tabs>
</div>
</div>
</div>
<!--components tabs end-->
</template>
in normal HTML and JQuery, i can load the data and the render the result and append it to the wanted tab how can we do this with vue, dose the dynamic component help in this case ?
I searched for a solution and found and implement the "Creating Vue.js Component Instances Programmatically"