Updating vue js value - vue.js

I want to update a placeholder (currentUsername) asynchronously with an actual value after loading/rendering the page.
I tried following a sample project (https://github.com/jackfranklin/vue2-demo-proj), but I can't correlate it with my setup. Using vuejs 2.0.
I can see the event is triggered, the call is made and something's returned, I've got no errors on my Chrome console, but nothing is updated in the UI. Why is that?
1) html file:
<script src="assets/js/data.js"></script>
2) data.js:
"use strict";
import * as DataXXX from './data.vue';
Vue.component("dataxxx", DataXXX);
var vm = new Vue({
el: "#app",
});
3) data.vue
<template>
<div>
<p v-if="currentUsername == null">
Null username
</p>
<p v-else>
Username: {{ currentUsername }}:
</p>
</div>
</template>
<script>
"use strict";
export default
{
created()
{
awr.EventsBus.$on("requestLoadData", this.loadData);
awr.EventsBus.$emit("requestLoadData", this.loadData);
},
destroyed()
{
awr.EventsBus.$off("requestLoadData", this.loadData);
},
methods:
{
loadData(name)
{
alert("got event");
this.currentUsername = name;
this.fetchGithubData(name);
},
fetchGithubData(name)
{
const url = "http://127.0.0.1/getUsername.php";
alert("requesting url: " + url);
fetch(url).then(response => response.text()).then(data => {
this.currentUsername = data;
console.log("got response: " + data);
});
}
},
data() {
return {
currentUsername: null
}
}
}
</script>

The if isn't re-evaluated when you get the response, so the placeholder isn't included in the page.
This line DOES update it, but it's just not shown: this.currentUsername = data;
Change it to something like:
<div>
Username: {{ currentUsername }}
</div

Related

Send value from API request from a component to another Vue.JS

I have a component which allow to retrieve the datas from a rest API...
My template allow user to enter an input (id) and to find the user associated with the user. I also have a component which is called dynamically.
<template>
<div>
<!-- form -->
<form>
<input type="text" v-model="userId" id="userId">
<button type="submit" class="btn btn-primary" #click="getUser($event); !isExistingUser">Get User</button>
</form>
<!-- result -->
<div v-if="!showComponent">
{{ user["id"] }} {{ user["username"] }} {{ user["email"] }}
<button #click="showComponent = !showComponent">Editer</button>
</div>
<!-- Edit the user -->
<div v-if="showComponent">
<edit-user :toUpdate="updateUser"></edit-user>
</div>
</div>
</template>
In the script part I have datas and methods :
The objective is to send the user that i collect and to send it to the update user. For this I created a data binding.
I also try to set the value of the object in the getUser method. And i can display the value.
<script>
import axios from "axios";
import EditUserForUpdate from "./EditUserForUpdate";
export default {
name: "FindUser",
components: {
"edit-user": EditUserForUpdate
},
data() {
return {
toUpdate: Object,
user: null,
isExistingUser: false,
userId: "",
userEmail:"",
userUsername: "",
showComponent: false
};
},
methods: {
getUser(event) {
axios
.get("http://localhost:4000/api/users/" + this.userId)
.then(response => {
console.log(response);
this.user = response.data.data;
var toUpdate = {};
toUpdate = { upUserName: this.user.username, upUserEmail: this.user.email, upId: this.user.id};
console.log(toUpdate);
});
}
}
};
</script>
Finally in the child component :
<script>
export default {
name: "EditUserForUpdate",
data: function () {
return {
updateUser: ''
}
},
props: {
updateUser: Object
},
methods: {
beforeMount () {
var updateUser = this.updateUser // save props data to itself's data and deal with it
console.log("userToUpdate : " + updateUser);
}
}
}
</script>
My issue is that I don't retrieve the data in the child module for an unknown reason.
The property is named toUpdate and not updateUser.
Update your prop accordingly in the EditUserForUpdate component:
props: {
toUpdate: Object
}
And of course, localize that object for manipulation:
beforeMount() {
this.updateUser = this.toUpdate
}

Click event on div to get innerText value and $emit with event-bus to another component not working

I have a list of divs that include product information which i get from an API call. In another component/view i want to display a single product information when the divs are clicked on.
So what i'm trying to do is retrieve the product id by accessing the event object when clicking on the divs then store that id in a variable (not data property) and then $emit it with the event-bus and then listen for it in my other component and use that id to make the API call to get the information for that single product. I'm not sure if this is the best way of doing what i want to do, but its the only way that comes to mind right now.
However so far i have gotten a few different errors and my component that displays the single product does not render.
This is the component that displays the list of products/divs
<template>
<div>
<div class="pagination">
<button :disabled="disabled" #click.prevent="prev()">
<i class="material-icons">arrow_back</i>
</button>
<span class="page-number">{{ currentPage }}</span>
<button #click.prevent="next()">
<i class="material-icons">arrow_forward</i>
</button>
</div>
<div class="products">
<div
class="product"
#click="getSingleBeer($event)"
v-for="product in products"
:key="product.id"
>
<h2 class="name">{{ product.name }}</h2>
<div class="image">
<img :src="product.image_url" />
</div>
<h3 class="tagline">{{ product.tagline }}</h3>
<h3 class="first-brewed">{{ product.first_brewed }}</h3>
<h3 class="abv">{{ product.abv }}%</h3>
<p class="id">{{ product.id }}</p>
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
import { eventBus } from "../main";
export default {
name: "Products",
data() {
return {
products: [],
currentPage: 1,
searchVal: ""
};
},
created() {
this.getBeers();
eventBus.$on("keyword", val => {
this.searchVal = val;
this.getBeersForSearch();
});
},
computed: {
apiUrl() {
return `https://api.punkapi.com/v2/beers?page=${this.currentPage}&per_page=16`;
},
apiUrlForSearch() {
return `https://api.punkapi.com/v2/beers?page=${this.currentPage}&per_page=12&beer_name=${this.searchVal}`;
},
disabled() {
return this.currentPage <= 1;
},
isFirstPage() {
return this.currentPage === 1;
}
},
methods: {
async getBeers() {
try {
const response = await axios.get(this.apiUrl);
this.products = response.data;
console.log(response);
} catch (error) {
console.log(error);
}
},
async getBeersForSearch() {
try {
this.currentPage = 1;
const response = await axios.get(this.apiUrlForSearch);
this.products = response.data;
console.log(response);
} catch (error) {
console.log(error);
}
},
getSingleBeer($event) {
const id = parseInt($event.target.lastChild.innerText);
eventBus.$emit("beer-id", id);
this.$router.push({ name: "Beer" });
}
}
};
</script>
And this is the component/view that is going to display info for the single selected product.
<template>
<div class="beer-container">
<div class="description">
<h2>{{ beer.description }}</h2>
</div>
<div class="img-name">
<h1>{{ beer.name }}</h1>
<img :src="beer.image_url" alt />
</div>
<div class="ingredients"></div>
<div class="brewer-tips">
<h2>{{ beer.brewers_tips }}</h2>
</div>
</div>
</template>
<script>
import { eventBus } from "../main";
import axios from "axios";
export default {
name: "Beer",
data() {
return {
beerId: null,
beer: []
};
},
created() {
eventBus.$on("beer-id", id => {
this.beerId = id;
this.getBeer();
console.log(this.beer);
});
},
methods: {
async getBeer() {
try {
const response = await axios.get(this.apiUrl);
this.beer = response.data[0];
console.log(response.data[0]);
} catch (error) {
console.log(error + "Eroorrrrrr");
}
}
},
computed: {
apiUrl() {
return `https://api.punkapi.com/v2/beers/${this.beerId}`;
}
}
};
</script>
Some of the errors i had so far:
1-the api call is made 2-3 simultaneously when i observe console logs instead of just once.
GET https://api.punkapi.com/v2/beers/null 400
Error: Request failed with status code 400Eroorrrrrr
GET https://api.punkapi.com/v2/beers/null 400
Error: Request failed with status code 400Eroorrrrrr
GET https://api.punkapi.com/v2/beers/null 400
Error: Request failed with status code 400Eroorrrrrr
2-The first time i click on the div it directs to the new route/component but i dont receive any errors and nothing seems to happen behind the scenes.
3- I have also been getting this error:
[Vue warn]: Error in v-on handler: "TypeError: Cannot read property 'innerText' of null"
And
TypeError: Cannot read property 'innerText' of null
My router.js
import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import Beer from "./views/Beer.vue";
Vue.use(Router);
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "home",
component: Home
},
{
path: "/beer",
name: "Beer",
component: Beer
}
]
});
UPDATE: I'm able to pass the data to the next component but when i click on the product divs the first time nothing happens, i only get directed to the next route/component but data does not get passed. And when i go back and click again,(without refreshing the page) the data gets passed but nothing renders on the component.
I believe you can simplify that a lot by changing your #click to be:
#click="getSingleBeer(product.id)"
Which should pass the id for you, so you can just do:
getSingleBeer(beerId) {
eventBus.$emit("beer-id", beerId);
this.$router.push({ name: "Beer" });
}

How to pass a variable and instantiate a new api request from my NavBar.vue component file to my News.vue views file?

I'm making an API request from https://newsapi.org/ and am able to do so with the created() method upon initiation. I have a component named Navbar.vue that includes buttons I'd like to use, upon click, to make a new api request and pass in a news source variable for the api request (e.g. 'cnn', 'fox-news'). Even though I've registered my News.vue in my Navbar.vue component, it doesn't appear I can use the created method to begin another instantiation. Here's a screen recording as well: https://drive.google.com/file/d/173x9PxLs5S2pWMYcHuXon0CQfoLwXNMT/view
I've tried calling NewsVue.created(source)
Top-Headlines/src/Components/Navbar.vue:
<template>
<div>
<b-navbar toggleable="lg" type="light" variant="success">
<b-container>
<b-navbar-brand href="#">Top Headlines</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-button-group>
<b-button variant="danger" v-on:click="getNews('cnn')">CNN</b-button>
<b-button variant="info" v-on:click="getNews('espn')">ESPN</b-button>
<b-button variant="warning" v-on:click="getNews('nbc-news')">NBC News</b-button>
</b-button-group>
</b-collapse>
</b-container>
</b-navbar>
</div>
</template>
<script>
// import News from '../views/News';
import NewsVue from '../views/News.vue';
export default {
// components: {
// NewsVue,
// },
data() {
return {
meal: ''
}
},
methods: {
getNews(source) {
console.log(NewsVue);
NewsVue.created(source);
}
}
}
Top-Headlines/src/views/News.vue:
<template>
<div class="articles-container">
<template v-for="article in headlines">
<div :key="article.publishedAt" class="article-container">
<div class="article-source">
<a v-bind:href="article.url">
<h5>{{ article.title }}</h5>
</a>
</div>
</div>
</template>
</div>
</template>
<script>
// # is an alias to /src
"use strict";
export default {
name: "news",
data() {
return {
headlines: [],
search: "",
newsSource: ""
};
},
methods: {
getTopHeadlines(newsSource) {
console.log(newsSource);
let url = '';
if (newsSource !== "" && newsSource !== undefined) {
url =
"https://newsapi.org/v2/top-headlines?" +
"pageSize=10&" +
"sources="+newsSource+"&" +
"apiKey=ab07dee4fb7e4f198621ab4da0b1e5e9";
} else {
url =
"https://newsapi.org/v2/top-headlines?" +
"country=us&" +
"pageSize=10&" +
"apiKey=ab07dee4fb7e4f198621ab4da0b1e5e9";
}
var req = new Request(url);
fetch(req)
.then(response => response.json())
.then(json => {
this.headlines = json.articles;
});
}
},
created(newsSource) {
this.getTopHeadlines(newsSource);
}
};
</script>
I expect the page to reload with news source filtered headlines.
Error messages:
"TypeError: this.getTopHeadlines is not a function
at Object.created (webpack-internal:///./node_modules/cache-"
created is normaly called by the system and has this set to the component. It seems you are trying to call it directly. You can either set this yourself by using apply, or by simply passing it in.
EITHER WAY, DON'T NAME THE FUNCTION CREATED, as it is reserved for the Vue lifecycle.
NewsVue.created2(source, NewsVue);
To call a function created2 and set the this context.
NewsVue.created2.call(NewsVue, source);
// or
NewsVue.created2.apply(NewsVue, [source]);
Either way, the function created2 will be invoked with this set to NewsVue and 1 parameter source.
Use a watcher function, then set the data from the watcher.
BTW, NewsView should take newsSource as a property, and I don't even see that component in your template... Perhaps that's the root of your issue. You need something like <NewsView :newsSource='newsSource'/> in the template. Then move newsSource to props, and make the watcher immediate.
export default {
name: "news",
data() {
return {
headlines: [],
search: "",
newsSource: ""
};
},
watch: {
newsSource(value) {
const newsSource = value;
console.log(newsSource);
let url = '';
if (newsSource !== "" && newsSource !== undefined) {
url =
"https://newsapi.org/v2/top-headlines?" +
"pageSize=10&" +
"sources=" + newsSource + "&" +
"apiKey=ab07dee4fb7e4f198621ab4da0b1e5e9";
} else {
url =
"https://newsapi.org/v2/top-headlines?" +
"country=us&" +
"pageSize=10&" +
"apiKey=ab07dee4fb7e4f198621ab4da0b1e5e9";
}
var req = new Request(url);
fetch(req)
.then(response => response.json())
.then(json => {
this.headlines = json.articles;
});
}
},
};

vue.js – get new data information

I'm building a chrome extension using vue.js. In one of my vue components I get tab informations of the current tab and wanna display this information in my template. This is my code:
<template>
<div>
<p>{{ tab.url }}</p>
</div>
</template>
<script>
export default {
data() {
return {
tab: {},
};
},
created: function() {
chrome.tabs.query({ active: true, windowId: chrome.windows.WINDOW_ID_CURRENT }, function(tabs) {
this.tab = tabs[0];
});
},
};
</script>
The Problem is, that the template gets the data before it's filled through the function. What is the best solution for this problem, when the tab data doesn't change after it is set once.
Do I have to use the watched property, although the data is only changed once?
// EDITED:
I've implemented the solution, but it still doesn't work. Here is my code:
<template>
<div>
<div v-if="tabInfo">
<p>set time limit for:</p>
<p>{{ tabInfo.url }}</p>
</div>
<div v-else> loading... </div>
</div>
</template>
<script>
export default {
data() {
return {
tabInfo: null,
};
},
mounted() {
this.getData();
},
methods: {
getData() {
chrome.tabs.query({ active: true, windowId: chrome.windows.WINDOW_ID_CURRENT }, function(tabs) {
console.log(tabs[0]);
this.tabInfo = tabs[0];
});
},
},
};
</script>
The console.log statement in my getData function writes the correct object in the console. But the template only shows the else case (loading...).
// EDIT EDIT
Found the error: I used 'this' in the callback function to reference my data but the context of this inside the callback function is an other one.
So the solution is to use
let self = this;
before the callback function and reference the data with
self.tab
You could initialize tab to null (instead of {}) and use v-if="tabs" in your template, similar to this:
// template
<template>
<div v-if="tab">
{{ tab.label }}
<p>{{ tab.body }}</p>
</div>
</template>
// script
data() {
return {
tab: null,
}
}
new Vue({
el: '#app',
data() {
return {
tab: null,
}
},
mounted() {
this.getData();
},
methods: {
getData() {
fetch('https://reqres.in/api/users/2?delay=1')
.then(resp => resp.json())
.then(user => this.tab = user.data)
.catch(err => console.error(err));
}
}
})
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<div v-if="tab">
<img :src="tab.avatar" width="200">
<p>{{tab.first_name}} {{tab.last_name}}</p>
</div>
<div v-else>Loading...</div>
</div>

Vue.js data: undefined

I am new to Vue.js.
Please advice me.
I get comments: undefined so comments are not displaying.
xhr is normal with 200.
Thank you
Thank you
Thank you
Thank you
Thank you
<template>
<div>
<ul class="media-list">
<li class="media" v-for="comment in comments">
{{ $comment.body }}
</li>
</ul>
</div>
</template>
<script>
export default {
data () {
return {
comments: []
}
},
props: {
postid: null
},
methods: {
getComments () {
this.$http.get('/blog/' + this.postid + '/comments').then((response) => {
this.comments = response.json().data;
});
}
},
mounted () {
this.getComments();
}
}
Basically there are two problems:
$comment don't exist
You have no data on response.json().data, that's why you get a undefined
I used a different API just to test it (as I don't have access to yours).
TEMPLATE
<div id="app">
<ul class="media-list">
<li class="media" v-for="comment in comments">
{{ comment.familyName + ', ' + comment.givenName }}
</li>
</ul>
</div>
SCRIPT
new Vue({
el: '#app',
data () {
return {
comments: []
}
},
props: {
postid: null
},
methods: {
getComments () {
this.$http.get('//ergast.com/api/f1/drivers.json').then((response) => {
this.comments = response.body.MRData.DriverTable.Drivers;
});
}
},
mounted () {
this.getComments();
}
});
Check out a working example here
this.comments = response.json().data;
console.log(this.comments) ;
to see what you get ;
you define comments=Array ;
maybe you get the response.json().data is not a Array;
Try using vm instead of this. In API response make sure what you are getting using console.log(). If response is already in json do not use response.json(). In HTML change $comment.body to comment.body. Make sure you have the body key in comments[] array.
<template>
<div>
<ul class="media-list">
<li class="media" v-for="comment in comments">
{{ comment.body }}
</li>
</ul>
</div>
</template>
<script>
export default {
data () {
return {
comments: [],
postid: null
}
},
props: {
},
methods: {
getComments () {
let vm = this;
vm.$http.get('/blog/' + vm.postid +
'/comments').then((response) => {
console.log(response)
vm.comments = response.data;
});
}
},
mounted () {
let vm = this;
vm.getComments();
}
}
}
:
My suggestion is to properly use try-catch statements.
I have found this is the safest and proper way to manage cases where variable could take undefined or null values, instead of trying to "if" everything.
try {
val = localStorage.getItem('accesstoken')
} catch (error) {
alert(error)
}
Take care!