I have this kind of objects in an array:
{
name: 'name1',
url: 'http://url-1.tld'
},
{
name: 'name2',
url: 'http://url-2.tld'
}
On div click, I want to to a window.location.href to the url, but I can't seem to get the url from the data to my method.
<div v-for="person in persons" v-on:click="select($event)"></div>
select: function(event) {
window.location.href( ??? )
}
Anybody have suggestions?
You need to pass the person as the argument to select, not $event:
<div v-for="person in persons" v-on:click="select(person)"></div>
select: function(person) {
window.location.href = person.url;
}
Related
I have this kind of objects in an array:
{
name: 'name1',
url: 'http://url-1.tld'
},
{
name: 'name2',
url: 'http://url-2.tld'
}
On div click, I want to to a window.location.href to the url, but I can't seem to get the url from the data to my method.
<div v-for="person in persons" v-on:click="select($event)"></div>
select: function(event) {
window.location.href( ??? )
}
Anybody have suggestions?
You need to pass the person as the argument to select, not $event:
<div v-for="person in persons" v-on:click="select(person)"></div>
select: function(person) {
window.location.href = person.url;
}
I have a table in Vue.js application, listing a URL and an Id. This URL is defined by the user, so I created and input component, with a input text, using the URL as value and the Id as parameter. The v-model of this component is an array, where I need to store data as JSON objects like this:
{
"id": 1,
"url": "www.some-url.com"
}
How can I catch changes in the url field and return for its parent to append in an array?
Component:
<template>
<div class="row">
<div class="col-md-12">
<input type="text"
class="form-control"
v-model="value.url">
</div>
</div>
</template>
<script>
export default {
name: 'inputUrl',
props: {
url: {
type: [String],
description: 'URL'
},
id: {
type: Number,
description: 'Id'
}
},
components: {
}
data() {
return {
value: {
id: this.id,
url: this.default
}
};
},
methods: {
},
mounted() {
},
watch: {
}
}
</script>
Usage:
<inputUrl
:id="1"
url="www.some-url.com"
v-model="array">
</inputUrl>
I passed the array variable to the InputUrl component then used v-on directive to passing the current input value to a custom function for appending the new values to the array variable.
Here an example.
When to use vue-router link as
<router-link to="/login">Login</router-link> it render to login view and <router-link :to="/login">Login</router-link> this one is the same.
What is the difference and why we use the colon and we must use it ?
The : is v-bind Shorthand syntax.
https://v2.vuejs.org/v2/guide/syntax.html#v-bind-Shorthand
If you want to use Javascript expressions then need to use :
let LoginUrl = '/login'
<router-link :to="loginUrl">Login</router-link>
// Another example
let student = {id: 521, name: 'Jhon Doe'}
<router-link :to="`students/${student.id}`"></router-link>
Without : You're just writing string inside to=""
Colon is shorthand for v-bind directive and you would use it to bind to computed property or method.
https://v2.vuejs.org/v2/guide/syntax.html#v-bind-Shorthand
Examples:
<!-- Static value -->
<router-link to="/login">Login</router-link>
<!-- Dynamic values-->
<router-link :to="`/user/${id}`">Login</router-link>
<router-link :to="getUserLink(id)">Login</router-link>
<router-link :to="currentUserLink">Login</router-link>
new Vue({
data() {
return {
id: 1
}
},
computed: {
currentUserLink() { return '/user/'+ this.id }
},
methods: {
getUserLink(id) {
return '/user/'+ id
}
}
});
i have a '/posts' route. This 'posts' route has a created() function which fetches data from an API via GET and outputs the data to the page.
Now I have a navbar which is included on every page. This navbar now has an input field where I can search certain posts by tags. This tag based search function is already working and runs via POST to an api.
Now the problem:
I write some tags into input field in the navigation and search for them. If I'm currently not at the posts route, the search works fine and I get directed to the posts route and see the tag related posts.
If I write some tags in the navbar input field and press the search button, WHILE i'm already on the posts route, nothing happens.
So if I'm in any other route then '/posts', the tag based search works great.
Thats why I think, the problem is, that I'm already on the '/posts' route. But it should also work this way! So I need something like a route link that replaces/refresh the route content?
Here is my code:
Relevant part of my navbar component:
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<router-link to="/posts" class="nav-link">Posts</router-link>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<div v-for="(tag, index) in tags" class="ml-sm-2">
<h6><span class="badge badge-light" #click="removeSearchTags(index)">{{ tag }}</span></h6>
</div>
<input class="form-control ml-1 mr-sm-2" type="text" v-model="tag" v-on:keyup.enter="pushToTags"
placeholder="Search Gaming, Youtube, DrunkSlut" aria-label="Search">
<router-link :to="{name: 'posts', params: { searchTags: tags }}" reload>
<button type="button" v-if="this.tags.length > 0"
class="btn btn-outline-light my-2 my-sm-0">Search
</button>
</router-link>
</form>
Whole posts component logic:
<script>
export default {
name: "posts",
data: function () {
return {
apiUrl: '/getPosts',
posts: '',
submitted: false,
first_page_url: '',
last_page_url: '',
current_page_url: '',
next_page_url: '',
prev_page_url: '',
lastPage: '',
current_page: '',
tags: [],
}
},
methods: {
getPosts: function (url) {
this.$http.get(url).then(function (data) {
this.posts = data.body.data;
this.first_page_url = data.body.first_page_url;
this.last_page_url = data.body.last_page_url;
this.next_page_url = data.body.next_page_url;
this.current_page = data.body.current_page;
this.prev_page_url = data.body.prev_page_url;
this.lastPage = data.body.last_page;
this.current_page_url = '/getPosts?page=' + this.current_page;
});
},
getPostByTags: function (url, tags) {
this.$http.post(url, {
tags: tags
}).then(function (data) {
this.posts = data.body.data;
this.first_page_url = data.body.first_page_url;
this.last_page_url = data.body.last_page_url;
this.next_page_url = data.body.next_page_url;
this.current_page = data.body.current_page;
this.prev_page_url = data.body.prev_page_url;
this.lastPage = data.body.last_page;
this.current_page_url = '/getPostByTags?page=' + this.current_page;
});
},
},
computed: {},
created() {
if (!this.$route.params.searchTags) {
this.getPosts(this.apiUrl);
} else {
this.getPostByTags('/getPostByTags', this.$route.params.searchTags);
}
},
}
</script>
The Main html file, where vueJS starts. There is only the navbar component, thats how it's included on any other route.
<div id="app">
<navbar></navbar>
<router-view></router-view>
</div>
Try to make your created as a watch
Something like:
watch: {
'$route.params.searchTags': {
deep: true,
immediate: true, // this triggers the watch on component creation, so you can remove the created hook content
handler() {
if (!this.$route.params.searchTags) {
this.getPosts(this.apiUrl);
} else {
this.getPostByTags('/getPostByTags', this.$route.params.searchTags);
}
}
}
}
I am fairly new to vue and can't figure out how to add data values within a template. I am trying to build a very basic form builder. If I click on a button it should add another array of data into a components variable. This is working. The I am doing a v-for to add input fields where some of the attributes are apart of the array for that component. I get it so it will add the input but no values are being passed into the input.
I have created a jsfiddle with where I am stuck at. https://jsfiddle.net/a9koj9gv/2/
<div id="app">
<button #click="add_text_input">New Text Input Field</button>
<my-component v-for="comp in components"></my-component>
<pre>{{ $data | json }}</pre>
</div>
new Vue({
el: "#app",
data: function() {
return {
components: [{
name: "first_name",
showname: "First Name",
type: "text",
required: "false",
fee: "0"
}]
}
},
components: {
'my-component': {
template: '<div>{{ showname }}: <input v-bind:name="name" v-bind:type="type"></div>',
props: ['showname', 'type', 'name']
}
},
methods: {
add_text_input: function() {
var array = {
name: "last_name",
showname: "Last Name",
type: "text",
required: "false",
fee: "0"
};
this.components.push(array);
}
}
})
I appreciate any help as I know I am just missing something obvious.
Thanks
Use props to pass data into the component.
Currently you have <my-component v-for="comp in components"></my-component>, which doesn't bind any props to the component.
Instead, do:
<my-component :showname="comp.showname"
:type="comp.type"
:name="comp.name"
v-for="comp in components"
></my-component>
Here is a fork of your fiddle with the change.
while asemahle got it right, here is a boiled down version on how to expose data to the child component. SFC:
async created() {
await this.setTemplate();
},
methods: {
async setTemplate() {
// const templateString = await axios.get..
this.t = {
template: templateString,
props: ['foo'],
}
},
},
data() {
return {
foo: 'bar',
t: null
}
}
};
</script>
<template>
<component :is="t" :foo="foo"></component>
It pulls a template string that is compiled/transpiled into a js-render-function. In this case with Vite with esm to have a client-side compiler available:
resolve: {
alias: {
// https://github.com/vuejs/core/tree/main/packages/vue#with-a-bundler
vue: "vue/dist/vue.esm-bundler.js",
the index.js bundle size increases by few kb, in my case 30kb (which is minimal)
You could now add some what-if-fail and show-while-loading with defineasynccomponent