Cannot update field value with Vue.js - javascript

I have been struggling with updating the value contained inside a paragraph of my page using Vue.js. Indeed as you can see below , in the axios statement of the vueLog Vue, I am trying to put a message "Welcome username" in the {{loggeg_in_msg}} field that is contained in my nav. ( I am getting this username from a get request using the access token that I stored in my cookies).
I actually placed a console.log in the then() statement to see whether I was attributing the proper value and it is returning the expected value. Then there must be a mistake with the this I am binding but I cannot see what I am having wrong.
Here are the snippets:
nav.html
<div th:fragment="nav" class="container">
<div class="row">
<div class="twelve columns">
<ul class="navMenu">
<li>Home</li>
<li>Login</li>
<li>Categories</li>
</ul>
</div>
<p id="loggedIn">{{logged_in_msg}}</p>
</div>
</div>
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head th:replace="fragments/header :: header('Home')" />
<body>
<div id="root">
<div th:replace="fragments/nav :: nav"></div>
<div Class="container"></div>
<div class="row">
<div class="twelve columns">
<h1>HKEstate</h1>
<ul>
<li v-for="post in posts">
<h3>{{post.title}}</h3>
<p>{{post.body}}</p>
</li>
</ul>
</div>
</div>
</div>
</div>
</body>
<div th:replace="fragments/footer :: foot"></div>
<script>
var app = new Vue({
el: '#root',
data : {posts: []},
mounted(){
this.fetchPosts();
},
methods: {
fetchPosts(){
axios.get("/posts").then(function(response){
this.posts = response.data;
}.bind(this));
},
getLink(post){
return '/post/' + post.id;
}
}
});
</script>
</html>
footer.html
<div th:fragment="foot" th:remove="tag">
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://vuejs.org/js/vue.js"></script>
<script src="/js/script.js"></script>
</div>
script.js
function getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
function isAnonymous(name){
return name == "anonymousUser";
}
var vueLog = new Vue({
el : "#loggedIn",
data : {logged_in_msg : ""},
mounted(){
var isLoggedIn = false;
if(!(getCookie("access_token")==null)){
axios.get("/getUsername?access_token=" + getCookie("access_token"))
.then(function(response){
this.logged_in_msg = "welcome "+response.data;
console.log(this.logged_in_msg)
}.bind(this))
.catch(function(error){
console.log("OK3:"+error.stack )
//TODO delete cookie?
}.bind(this));
}
}
});
So far when I am inspecting my page all that I am having is an empty paragraph . Is there anything that I missed?

Related

Vue : Accessing Nested Object Component's Values

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>

Can't access a nested JSON object in HTML

AngularJS V1.6.4
$scope.aCourse["name"] is logged to console correctly, but in the HTML code nothing is populated into the screen.
$scope.getCourse = function(idd){
$http.defaults.headers.common['Authorization'] = 'Basic ' + btoa($cookieStore.get('username') + ':' + $cookieStore.get('password') );
$http({
method: 'GET',
url: 'http://localhost:8080/course/'+idd,
}).then(function successCallback(response) {
$scope.aCourse = response.data;
console.log($scope.aCourse["name"]);
window.location = "/website-take-course.html";
}, function errorCallback(response) {
alert("Course data in fetching failed");
});
}
HTML Code:
<div class="page-section padding-top-none" ng-repeat="c in aCourse" >
<div class="media media-grid v-middle">
<div class="media-left">
<span class="icon-block half bg-blue-300 text-white">1</span>
</div>
<div class="media-body" >
<h1 class="text-display-1 margin-none" >{{c.name}}</h1>
</div>
</div>
<br/>
<p class="text-body-2">{{c.description}}</p>
</div>
Based on your post, it lookes like $scope.aCourse is a object, not an array.
change it as follows,
<div class="page-section padding-top-none" ">
<div class="media media-grid v-middle">
<div class="media-left">
<span class="icon-block half bg-blue-300 text-white">1</span>
</div>
<div class="media-body">
<h1 class="text-display-1 margin-none">{ aCourse.name }}</h1>
</div>
</div>
<br/>
<p class="text-body-2">{{aCourse.description}}</p>
</div>
or use something like this to iterate over object,
<div ng-repeat="(key,value) in aCourse">
{{key}} : {{value}}
</div>
DEMO
var app = angular.module('filterApp', []);
app.controller('myCtrl', function($scope) {
$scope.aCourse = {
"content": "SO",
"description": "Programmers"
};
});
<!DOCTYPE html>
<html >
<head>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/1.4.7/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="filterApp" ng-controller="myCtrl">
<div ng-repeat="(key,value) in aCourse">
{{key}} : {{value}}
</div>
</body>
</html>
There could be a two situations :
1. $scope.aCourse is an array of objects [{},{},{}].
DEMO
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) {
$scope.aCourse = [
{
"name": "alpha",
"description" : "description1"
},
{
"name": "beta",
"description" : "description2"
},
{
"name": "gamma",
"description" : "description3"
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<div class="page-section padding-top-none" ng-repeat="c in aCourse" >
<div class="media-body" >
<h1 class="text-display-1 margin-none" >{{c.name}}</h1>
</div>
<p class="text-body-2">{{c.description}}</p>
</div>
</div>
2. $scope.aCourse is an Object {......}.
DEMO
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) {
$scope.aCourse = {
"name": "alpha",
"description" : "description1"
};
console.log($scope.aCourse["name"]);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<div class="page-section padding-top-none" ng-repeat="(key, value) in aCourse" >
<div class="media-body" >
<h1 class="text-display-1 margin-none" >{{value}}</h1>
</div>
</div>
</div>
In your angular code you are setting aCourse to the response data. You then access the data as an object with:
$scope.aCourse["name"]
Then in your html you are running an ng-repeat on $scope.aCourse as if it were an array of objects:
<div class="page-section padding-top-none" ng-repeat="c in aCourse" >
You would either need to make aCourse an array of objects to use your current html, or update your html and access the object in aCourse with aCourse.name and aCourse.description.

Vue 2 data returned by component data function are not defined

I am developing an application and I am using Vue 2 as my javascript framework, I tried to declare some components and use them in my html pages
this is my html:
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.3.1/css/bulma.css" />
</head>
<body>
<div id="modal_element" >
<modal v-if="showModal" ></modal>
<button #click="showModal = true" >Show Modal</button>
</div>
<div id="root">
<ul>
<li v-for="task in incompeletedTasks" >
{{ task.description }}
</li>
</ul>
</div>
</body>
<script src="https://unpkg.com/vue#2.1.10/dist/vue.js" ></script>
<script src="main.js"></script>
<script src="modal.js" ></script>
<script>
let main_data = {
tasks : [
{ description : "Go to the store ", completed : true },
{ description : "Leave the store" , completed : false }
]
}
new Vue({
el : "#root",
data : main_data,
computed : {
incompeletedTasks() {
return this.tasks.filter(task => !task.completed);
}
}
});
and this the modal.js file:
Vue.component('modal',{
template : '<div id="modal_element">
<div class="modal is-active">
<div class="modal-background"></div>
<div class="modal-content box">
<p>
Some Modal Text here ...
</p>
</div>
<button class="modal-close" #click="showModal = false" >
</button>
</div>',
data : function(){
return {
showModal : false
};
}
});
new Vue({
el : '#modal_element',
});
but the modal is not displayed, and I am getting the following error in the chrome console
[Vue warn]: Property or method "showModal" is not defined on the instance
but referenced during render. Make sure to declare reactive data
properties in the data option.
Question:
what modification do I have to make to get the code working? and html page successfully displays modal?
I think there are a couple of things.
You are creating 2 vue instances in this example (#root and #modal-element), so the data will not be able to be shared unless you have some store. Much better to have just a single instance and put components in that.
You will need to pass the component into the vue instance in order for it to be aware of the component.
Here is an example with alot of the stuff trimmed out.
https://jsfiddle.net/Austio/vhgztp59/2/
The gist of it is
var component = ...createComponentStuff
new Vue({
...otherVueStuff,
components: [component]
})

meteor saying Iron Router is unresolved with Intellij

I'm using Intellij and Meteor to make an application and I'm trying to use Iron Router to create multiple pages, but when I call the Router in the Javascript file, it says that Router is an unresolved variable and that route is an unresolved function or method. I've checked the meteor folder and it appears that all the Iron Router files loaded fine. At the bottom of the root page I am working on it says
Oops, looks like there's no route on the client or the server for url:
"http://localhost:3000/."
If I navigate to http://localhost:3000/about, which is the only page I have a route set up for yet, the page is blank, except for my nav bar.
Here is my javascript file...
Items = new Mongo.Collection("items");
Found_items = new Mongo.Collection("found_items");
Router.route('home', {path: '/'}); // Add this route
Router.route('about', {path: '/about'});
if (Meteor.isClient) {
// This code only runs on the client
Template.body.helpers({
items: function () {
return Items.find({});
},
found_items: function () {
return Found_items.find({});
},
priceSum: function(){
var userItems = Found_items.find({
userId: this._id
}).fetch();
var prices = _.pluck(userItems, "price");
var totalTaxed = _.reduce(prices, function(sum, price){
var total = sum + parseFloat(price);
return total + (total * 0.04712);
}, 0);
return totalTaxed.toFixed(2);
},
calcTax: function () {
var userItems = Found_items.find({
userId: this._id
}).fetch();
var prices = _.pluck(userItems, "price");
var tax = _.reduce(prices, function(sum, price){
return (sum + parseFloat(price)) * 0.04712;
}, 0);
return tax.toFixed(2);
}
});
Template.body.events({
"submit .new-item": function (event) {
event.preventDefault();
var text = event.target.text.value;
Items.insert({
text: text,
createdAt: new Date(),
owner: Meteor.userId(),
username: Meteor.user().username
});
event.target.text.value = "";
}
});
Template.item.events({
"click .found": function (event, template) {
event.preventDefault();
var price = template.find('[name="price"]').value;
var text = template.find('.text').textContent;
Items.remove(this._id);
Found_items.insert({
text: text,
price: price
});
}
});
Template.body.events({
"click .remove": function(event) {
event.preventDefault();
Found_items.remove(this._id);
}
});
Accounts.ui.config({
passwordSignupFields: "USERNAME_ONLY"
});
}
And here is the HTML file
<head>
<title>Grocery List</title>
</head>
<template name="home">
<body>
<div>
<ul class="menu">
<li class="menuItem">{{> loginButtons}}</li>
<li class="menuItem">Home </li>
<li class="menuItem">About</li>
</ul>
</div>
{{#if currentUser}}
<div class="container">
<header>
<h1 id="title">Grocery List</h1>
<form class="new-item">
<input type="text" name="text" placeholder="Type to add new items" />
</form>
</header>
<ul>
{{#each items}}
{{> item}}
{{/each}}
</ul>
</div>
<div class="container">
<header>
<h1>Items Found</h1>
</header>
<ul>
{{#each found_items}}
{{> found}}
{{/each}}
</ul>
</div>
<div class="container">
<header>
<h3>
Tax: ${{calcTax}}
</h3>
<h2>
Total: ${{priceSum}}
</h2>
<button class="save">Save list</button>
</header>
</div>
{{else}}
<h3>Please log in first.</h3>
{{/if}}
</body>
</template>
<template name="item">
<li>
<button class="found">Got it!</button>
<input type="number" name="price" placeholder="Sale Price" />
<span class="text">{{text}}</span>
</li>
</template>
<template name="found">
<li>
<button class="remove">×</button>
<span class="text">{{text}}</span>
<span class="price">{{price}}</span>
</li>
</template>
<template name="about">
<head>
<title>About Grocery List</title>
</head>
<body>
<div>
<ul class="menu">
<li class="menuItem">{{> loginButtons}}</li>
<li class="menuItem">Home </li>
<li class="menuItem">About</li>
</ul>
</div>
<div class="container">
<header><h1>About</h1></header>
<p>This application was created using Meteor. It can be used to make, save and update grocery lists. Once the user is in the store, they can use it to check off items on the list, put in the price and see the total, with tax.<br>
Users can also save their previous lists to either reuse them, or compare current prices to previous ones.<br>
Future implementations of this page would also allow the user to change the tax rate depending on their location, and include coupons and other discounts in the pricing.</p>
</div>
</body>
</template>
Always add a route for the root.
Items = new Mongo.Collection("items");
Found_items = new Mongo.Collection("found_items");
Router.route('home', {path: '/'}); // Add this route
Router.route('about', {path: '/about'});
BTW, you have a head and body section within your template. That is rendered but does not have an effect in your browser.
Use the following syntax with IR's template helper pathFor:
<ul class="menu">
<li class="menuItem">{{> loginButtons}}</li>
<li class="menuItem">Home</li>
<li class="menuItem">About</li>
</ul>
In order to get your code working, I also fixed a couple of issues:
Removed head and body tags in templates.
Renamed Template.body.helpers to Template.home.helpers.
Renamed Template.body.events to Template.home.events.
Now it is adding new items to the collection and showing items.
you have to add a route with / to call localhost:3000
routing example
Router.configure({
layoutTemplate: 'layout',
});
Router.route('/', function () {
this.render('home');
},{
name: 'home'
});
Router.route('/about', function () {
this.render('about');
},{
name: 'about'
});
html
<template name="layout">
{{> yield}}
</template>
<template name="home">
<p>i am the homepage</p>
</template>
<template name="about">
<p>i am the about page</p>
</template>

Update page with items added via text field in Ember

I'm working on my first Ember app. It's a variation of a to do app. You type in a value, hit submission button and the page should update with each new item added using two-way data binding.
Every new item gets added to an array of object literals.
So adding new objects to the array and then looping through each item and printing it to the page is working just fine. Only problem is the page never updates with new items added via the input field.
I thought creating a custom view (App.ReRenderUserList in this instance) and adding .observes like they talk about in a previous question might be the answer, but that didn't seem to work.
Here's my code. Let me know if there's anything else I need to add. Thanks for your help.
index.html
<script type="text/x-handlebars" data-template-name="add">
{{partial "_masthead"}}
<section>
<div class="row">
<div class="column small-12 medium-9 medium-centered">
<form {{action "addToList" on="submit"}}>
<div class="row">
<div class="column small-8 medium-9 no-padding-right">
{{input type="text" value=itemName}}
</div>
<div class="column small-4 medium-3 no-padding-left">
{{input type="submit" value="Add +"}}
{{!-- clicking on this should add it to the page and let you keep writing --}}
</div>
</div>
<!-- /.row -->
</form>
</div>
<!-- /.column -->
</div>
<!-- /.row -->
</section>
<section>
<div class="row">
<div class="column small-12 medium-9 medium-centered">
<div class="list">
{{#each userItems}}
<div class="column small-16">
{{#view App.ReRenderUserList}}
<div class="item">{{name}}</div>
{{/view}}
</div>
<!-- /.column -->
{{/each}}
</div>
<!-- /.list -->
</div>
<!-- /.column -->
</div>
<!-- /.row -->
</section>
</script>
<!-- END add items template -->
pertinent app.js code:
var itemLibrary = [
{
'name' : 'bread'
},
{
'name' : 'milk'
},
{
'name' : 'eggs'
},
{
'name' : 'cereal'
}
];
var userLibrary = [];
App.AddRoute = Ember.Route.extend({
model: function() {
return Ember.RSVP.hash({
presetItems: itemLibrary,
userItems: userLibrary
});
}
});
App.AddController = Ember.ObjectController.extend({
actions: {
// add the clicked item to userLibrary JSON object
addToList: function(){
var value = this.get('itemName'); // gets text input value
userLibrary.push({
name: value // this is just echoing and not adding my new items from the form.
}); // adds it to JSON Object
console.log(userLibrary);
}
}
});
App.ReRenderUserList = Ember.View.extend({
submit: function(){
console.log('rerendered!');
}
});
You should use the pushObject method instead of the push method. This will update the bindings..
App.AddController = Ember.ObjectController.extend({
actions: {
// add the clicked item to userLibrary JSON object
addToList: function(){
var value = this.get('itemName'); // gets text input value
userLibrary.pushObject({
name: value // this is just echoing and not adding my new items from the form.
}); // adds it to JSON Object
console.log(userLibrary);
}
}
});

Categories

Resources