I am trying to pass an account to a removal method in Vue. I output the account right before the router-link and it shows the correct one, but outputting account in the method shows a different one.
HTML
// OUTPUTTING
{{chosenAccount}}
// ROUTER CLICK
<router-link #click.native="remove(chosenAccount)" to="/summary/" text="summary"><span cursor: pointer;" title="Summary"></span></router-link>
JS
methods:{
remove(account){
console.log('removed ',account);
this.removeAccountData(account);
},
},
The console.log in remove shows my other account and not the one I have selected on the page.
Am I missing anything?
Edit:
<template>
<div id="container" >
<div id="header">
<router-link #click.native="remove(chosenAccount, $event)" to="/summary/" text="summary"><span cursor: pointer;" title="Summary"></span></router-link>
</div>
<div id="content" >
<div id="settings" class="text-center" style="margin-left: -4px;">
<h3 style="color:#1173BD;"><span v-text="chosenAccount.network_name"></span></h3>
<!-- OUTPUTS ACCOUNT #2 (CORRECT) IN LOCAL STORAGE-->
{{chosenAccount}}
<h4>has been removed</h4>
<h3>
<router-link #click.native="remove(chosenAccount, $event)" to="/summary/" text="summary"><span cursor: pointer;" title="Summary"></span></router-link>
</h3>
</div>
</div>
<div id="footer" style="text-align:center;">
<router-link to="/" text="add_new_account"><span aria-hidden="true"> Add New Account</span></router-link>
</div>
</div>
</template>
<script>
import axios from "axios"
import {dataGetter} from "#/datagetter/dataGetter";
export default{
name:"removed",
mixins:[dataGetter],
data(){
return{
}
},
methods:{
getNewData(){
this.getData();
},
remove(account, event){
// OUTPUTS ACCOUNT #1 (INCORRECT) IN LOCAL STORAGE
console.log(account);
},
},
computed:{
networkName(){
let account = this.account;
if( account != undefined){
return account.network_name;
}
return "";
},
}
}
</script>
Related
I'm beginner in VueJS and hoping for your help.
I'm trying to create Weather forecast app based on OpenWeatherMap API.
The concept is such that:
Enter some location to input on homepage and click to search button. (in my code it's a component Search.vue)
Redirecting to another page and show results - current weather and forecast for next 6 days. (component Weather.vue)
I created function with two consistent fetch calls. First fetch taking entered input query and return needed data from Current Weather Data API. After that, function run second fetch to One Call API based on latitude longitude from first fetch.
Everything is working and showing fine, but i don't undestand why i have an error Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '1') in console:
Сan someone know how to fix this error?
My Search.vue (homepage) component:
<template>
<div class="row">
<div class="search-col col">
<div class="search-box">
<input
type="text"
class="search-bar"
placeholder="Location"
v-model="query">
<router-link :to="{name: 'DetailedWeather', params: { query: query }}" class="btn-search">
<i class="fas fa-search"></i>
</router-link>
</div>
</div>
</div>
</template>
My Weather.vue (weather results showing page) component:
<template>
<div class="row" v-if="typeof weather.main != 'undefined'">
<div class="weather-col col">
<div class="weather-app">
<div class="weather-box">
<div class="weather-top-info">
<div class="clouds-level"><span class="icon"><i class="fas fa-cloud"></i></span> {{ weather.clouds.all }}%</div>
<div class="humidity"><span class="icon"><i class="fas fa-tint"></i></span> {{ weather.main.humidity }}%</div>
</div>
<div class="weather-main-info">
<div class="temp-box">
<div class="temp-main">{{ Math.round(weather.main.temp) }}</div>
<div class="temp-inner-box">
<div class="temp-sign">°C</div>
<div class="temp-max"><span class="icon"><i class="fas fa-long-arrow-alt-up"></i></span> {{ Math.round(weather.main.temp_max) }}°</div>
<div class="temp-min"><span class="icon"><i class="fas fa-long-arrow-alt-down"></i></span> {{ Math.round(weather.main.temp_min) }}°</div>
</div>
</div>
<div class="weather-desc">{{ weather.weather[0].description }}</div>
<div class="weather-icon">
<img :src="'http://openweathermap.org/img/wn/'+ weather.weather[0].icon +'#4x.png'">
</div>
</div>
<div class="weather-extra-info">
<div>Feels like: <span>{{ Math.round(weather.main.feels_like) }}°C</span></div>
<div>Sunrise: <span>{{ weather.sys.sunrise }}</span></div>
<div>Sunset: <span>{{ weather.sys.sunset }}</span></div>
</div>
</div>
</div>
</div>
<div class="forecast-col col">
<div class="row">
<div class="forecast-item-col col" v-for="day in forecastDays" :key="day">
<div class="forecast-box">
<div class="forecast-date">{{ forecast.daily[day].dt }}</div>
<div class="forecast-temp">{{ Math.round(forecast.daily[day].temp.day) }}°C</div>
<div class="forecast-icon"><img :src="'http://openweathermap.org/img/wn/'+ forecast.daily[day].weather[0].icon +'#2x.png'"></div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="actions-col col">
<router-link :to="{name: 'Search'}" class="btn btn-default">
Back to search
</router-link>
</div>
</div>
</template>
<script>
export default {
name: 'Weather',
props: ['query'], //getting from homepage
data() {
return {
api_key:'b7fe640e9a244244a6f806f3a6cbf5fc',
url_base:'https://api.openweathermap.org/data/2.5/',
forecastDays: 6,
weather: {},
forecast: {}
}
},
methods: {
fetchWeather(){
// first call
fetch(`${this.url_base}weather?q=${this.query}&units=metric&appid=${this.api_key}`)
.then(response =>{ return response.json() }).then(this.setResults);
},
setResults(results){
this.weather = results;
// consistent second call
fetch(`${this.url_base}onecall?lat=${results.coord.lat}&lon=${results.coord.lon}&exclude=current,minutely,hourly,alerts&units=metric&appid=${this.api_key}`)
.then(data =>{ return data.json() }).then(this.setForecast);
},
setForecast(results){
this.forecast = results
},
},
created() {
this.fetchWeather();
}
</script>
My router/index.js file:
import { createRouter, createWebHashHistory } from 'vue-router'
import Search from '../components/Search.vue'
import Weather from '../components/Weather.vue'
const routes = [
{
path: '/',
name: 'Search',
component: Search
},
{
path: '/detailed-weather',
name: 'DetailedWeather',
component: Weather,
props: true
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
From what I guess (given the code and the error), there might be an issue with the objects you are receiving from the API.
The error message suggests you are trying to read something from an array at a specific index that is undefined.
The only occurrence in your code that could cause this error is from the template, where you are reading, for example:
{{ forecast.daily[day].dt }}
{{ Math.round(forecast.daily[day].temp.day) }}
I can't tell exactly which one is it, but try to double check the shape of the objects you are working with.
Everything works fine but when i reload the page i get the error window is not defined
I have added it to plugins and I have tried both ssr:false and mode:'client'
I think the problem is Nuxt doesn't apply the config to the Vue when reloading the page and use the server side to render the code.
plugins: [
{ src: '~/plugins/lightbox.js', ssr:false }
],
this is the plugin file
// plugins/lightbox.js
import GLightbox from 'glightbox'
import '../node_modules/glightbox/dist/css/glightbox.css'
this is a single page that is using the Glightbox library
_post.vue
<template>
<div class="main">
<div class="wrapper">
<div class="container">
<h2 class="heading">{{ data.title }}</h2>
<p>{{ data.description }}</p>
</div>
<div>
<div class="gallery">
<div v-for="item in data.images" :key="item.id">
<!-- <img class="image" :src="item.image" alt=""> -->
<a #mouseenter.prevent="setLightBox" :href="item.image" class="glightbox">
<figure>
<img :src="item.image" class="image">
</figure>
</a>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import GLightbox from 'glightbox'
export default {
// transition:'slide-fade',
async asyncData({ $axios, params }) {
const data = await $axios.$get(`api/v1/projects/${params.post}`)
console.log(data)
return { data }
},
data(){
return {
lightbox: ''
}
},
methods: {
setLightBox(){
this.lightbox = GLightbox({
touchNavigation: true,
loop: false,
})
},
toggleLightBox(){
this.lightbox.open()
}
}
}
</script>
I quite new to Vue js I am trying to use the computed method to create a search bar to only search through the name but I'm getting "this.info.filter" is not a function
<template>
<div class="container">
<input type="text" v-model="search" placeholder="Search by name">
<div class="content" v-for="student in filterName " v-bind:key="student.id">
<img class="image" :src="student.pic" alt="">
<div class="student-info">
<h1 class="info">{{student.firstName +" "+ student.lastName}}</h1>
<div class="infomation">
<p class="cop">{{ student.company }}</p>
<p class="ski">{{ student.skill }}</p>
<p class="email">{{ student.email }}</p>
<p class="grade">{{ student.grades }}</p>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "Student.vue",
data() {
return {
students: '',
search: ''
}
},
mounted() {
axios
.get('https://api.hatchways.io/assessment/students')
.then((res) => {
this.students = (res.data.students)
})
},
computed :{
filterName:function (){
return this.info.filter((student)=>{
return student.company.matcth(this.search);
})
}
}
}
</script>
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
First time using StackOverflow too please ignore the errors
I don't see a declaration/initialization for this.info anywhere in your code.
The reason you're getting that error is because filter is trying to run on an undefined variable (this.info is undefined).
You might want to initialize that to an empty array within data.
I have problems accessing this "name" property on the component. I can only access it statically.
<template>
<div class="col-md-12">
<p
v-for="channel in channels"
:key="channel.id"
class="channel"
:class="{ 'active': channel.id == activeChannel }"
#click="setChannel(channel.id)">
{{ channel.users[0].name }}
</p>
</div>
</template>
Here is an Image of my Vue Devtools
So I have an v-for loop over channels, and I want to: Access the Usernames for each channel (if it is not my own preferably as "username" is set on my own i think its easy to exclude it right?) So that in the end In Channel 1 when there are 2 Users , I want to show the corresponding username, so the "other username", the one i am chatting with, and he should see my name that is the initial goal.
I thought of doing something like this:
<template>
<div class="col-md-12">
<p
v-for="channel in channels"
:key="channel.id"
class="channel"
:class="{ 'active': channel.id == activeChannel }"
#click="setChannel(channel.id)">
<!-- {{ channel.users[0].name }} -->
<span v-for="user,key in channel">{{key}}</span>
</p>
</div>
it at least displays the content of the channels object for each channel, but something like this isnt gonna work: key.user.name , unfortunately im stuck here. please help :)
edit: here is a dd() of the view
click
EDIT 2: Parent Data Provided:
//chat-app.blade.php
<div id="app">
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Chats</div>
<vue-chat :channels="{{ $channels }}" ></vue-chat>
</div>
</div>
</div>
</div>
</div>
</div>
//<vue-chat> component
<template>
<div class="chat">
<div class="container">
<div class="row">
<div class="col-md-3">
<vue-chat-channels
:channels="channels"
:active-channel="activeChannel"
#channelChanged="onChannelChanged"
:username="sername"
></vue-chat-channels>
</div>
<div class="col-md-3">
<vue-chat-messages :messages="messages"></vue-chat-messages>
</div>
<div class="col-md-3">participants</div>
</div>
<div class="message-input-wrapper col-md-12"><vue-chat-new-message :active-channel="activeChannel"
:username="username"></vue-chat-new-message></div>
</div>
</div>
</template>
<script>
export default {
props: ["channels"],
data() {
return {
activeChannel: this.channels[0].id,
messages: [],
username: ''
};
},
methods: {
fetchMessages() {
let endpoint = `/channels/${this.activeChannel}/messages`;
axios.get(endpoint).then(({ data }) => {
this.messages = data;
});
},
onChannelChanged(id) {
this.activeChannel = id;
this.fetchMessages();
}
},
created() {
this.fetchMessages();
axios.get('/userfetch').then( ({data}) => {
console.log("Current User: "+data.name);
this.username = data.name;
});
console.log(this.channels[0].name);
// for (let channel of this.channels) {
this.channels.forEach(channel => {
// Channelname
window.Echo.channel('presence-'+channel.name)
.listen('MessageSent', (channel) => {
console.log(channel.data.message);
this.messages.push({ message: channel.data.message, author_username: channel.data.author_username});
if (this.activeChannel == channel.id) {
console.log("received message");
}
});
});
}
};
</script>
<style>
</style>
//ChatController.php
public function index()
{
$channels = Channel::with('users')->whereHas('users', function($q) {
$q->where('user_id',Auth::id());
})->get();
$user = Auth::user()->name;
return view('chat-app' , compact('channels','user'));
}
Short Explanation: ChatController returns the blade view, which has the data channels and user (my username) , and then vue comes into play which should pass down the prop of my username but i couldnt get it to work just yet
So you need to access users in every channel.
You can try like this:
<div class="col-md-12">
<p
v-for="channel in channels"
:key="channel.id"
class="channel"
:class="{ 'active': channel.id == activeChannel }"
#click="setChannel(channel.id)">
<span v-for="user in channel.users">
{{ user.name }}
</span>
</p>
</div>
This should work. If you have errors provide it here.
If you need to compare every user you can do it simply with v-if:
<span v-for="user in channel.users">
<span v-if="user.name === parentdata">
{{ user.name }}
</span>
</span>
I would like to know how to make the contents object visible in the video.vue component.
This is the Video.vue components. This component is where I want to access the content object that is defined in the Home.vue component.
<template>
<div>
<h1>{{title}}</h1>
</div>
</template>
<script>
export default {
data() {
return {
title: 'Video Section'
}
}
}
</script>
This is the Home.vue component:
<template>
<div class="container">
<div class="column is-one-third" v-for="content in contents.results" :content="content" :key="content.id">
<div v-show="loaded" class="loader"></div>
<div class="card" >
<div class="card-image">
<figure class="image">
<img :src="imageUrl + content.backdrop_path" alt="Image">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-left">
<figure class="image is-25x25">
<img id="poster-image" :src="imageUrl + content.poster_path" alt="Image">
</figure>
</div>
<div class="media-content">
<p id="movie-title" class="title is-4 no-padding">{{content.original_title}}</p>
<p><span class="title is-6"><i class="fas fa-star">{{" " + content.vote_average}}</i></span></p>
<p class="subtitle is-6"><i class="fas fa-calendar-alt">{{" " + content.release_date}}</i></p>
</div>
</div>
<div class="content">
{{ content.overview }}
<div class="background-icon"><span class="icon-twitter"></span></div>
</div>
<div id="footer-card-icons">
<i class="fas fa-info-circle"></i>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default{
data: () => ({
contents: [],
baseurl: 'https://api.themoviedb.org/3',
apikey: '16667866c29ba1bc29e687b4892b8d5c',
imageUrl: 'https://image.tmdb.org/t/p/w1280',
loaded: true,
}),
created: function(){
this.fetchData();
},
methods:{
fetchData: function(){
console.log('fetch data')
this.$http.get(this.baseurl + '/discover/movie?api_key=' +
this.apikey + '&sort_by=popularity.desc').then(response =>{
this.contents = response.body;
this.loaded = false;
});
}
}
}
</script>
As Emile’s commented, you should use props in order to be able to pass data from parent to child component.
In your Home.vue, add:
<videos :content=“contents”></videos>
But if your contents data type is Array:
<videos v-for=“content in contents” :key=“content.id” :content=“content”></videos>
Notice that if you use v-for to loop a component, you need to add key attribute also.
Finally, in your Video.vue, you need to define the props like below:
<template>
<div>
<p>{{ content.overview }}</p>
</div>
</template>
<script>
export default {
props: [‘content’],
data() {
return {
title: 'Video Section'
}
}
}
</script>
Remember, props are reactive. It will respond to any updates or changes in content.
UPDATE: It seems you have not properly declared your component. See codepen link. Better if you could declare any other components as Single File Components as explained here.