Vue Computed Property Setup Issues - javascript

I have the following JS that I'm trying to translate to Vue JS. I was told a computed property would be the way to go. I'm a little confused on computed properties still. I know how I want it to function, I want it's input to be the key of the item in the list. And I want the output to be a 'related' array that I can then loop through in sub list. If you are having trouble visualizing, please see this CodePen Any help would be awesome.
// Initialize Firebase
const db = firebase
.initializeApp({
databaseURL: "...firebaseio.com"
})
.database();
const contentRef = db.ref("a");
const relatedRef = db.ref("test");
new Vue({
el: "#app",
data: {
related: {}
},
firebase: {
content: contentRef,
related: relatedRef
},
});
var theKey = "objectb"
function getDiscoverBarContent(key, cb) {
relatedRef.child(key).on("child_added", snap => {
let relateRef = contentRef.child(snap.key);
relateRef.once("value", cb);
});
}
getDiscoverBarContent(theKey, snap => {
var snapVal = snap.val();
console.log(snapVal)
});
HTML
<div id="app">
<div>
<h2>Content</h2>
<pre><code>{{content}}</code></pre>
</div>
<div>
<h2>'Related' Content</h2>
<pre><code>{{related}}</code></pre>
</div>
<div>
<h2>'Results'</h2>
<ul>
<li v-for="thing in content">{{thing.name}}
<ul>
<li v-for="relation in related">{{relation.name}}</li>
</ul>
</li>
</ul>
</div>
</div>
EDIT: My attempt: CodePen
computed: {
relatedThings: function () {
var theKey = "objectb"
var output = []
function getDiscoverBarContent(key, cb) {
relatedRef.child(key).on("child_added", snap => {
let relateRef = contentRef.child(snap.key);
relateRef.once("value", cb);
});
}
getDiscoverBarContent(theKey, snap => {
var snapVal = snap.val();
console.log(snapVal)
var output = snapVal
});
return snapVal;
}
}
And Error:
ReferenceError: snapVal is not defined.
Please note, this is my attempt and I am not certain that it is going to work.
I should add...my JS skills are lacking. I know why this issue is happening but not sure how to fix.

Related

Mixpanel mock continuously comes back as undefined

I have a very basic static app that has business logic to redirect a user based on what element they click in the UI. I added Mixpanel, and track an event before the user is redirected. I'm trying to create tests using the Jest testing framework, but am having difficulties mocking the track method invocation on mixpanel.
The crux of the issue is I'm unable to mock mixpanel while running tests. I've read the Jest documentation and searched the community for answers, but every time I run tests, it fails with TypeError: Cannot read property 'track' of undefined. You'll have to forgive me if it is something obvious, JavaScript is not my native programming language, so when it comes time to build tests, I'm rusty at it. :)
index.html
<!doctype html>
<html class="no-js" lang="">
<head>
<!-- start Mixpanel -->
<script type="text/javascript">...Mixpanel script</script>
<script src="js/scripts.js"></script>
<script type="text/javascript">
const { sources } = window.parseSourcesFromURL(window.location.href)
const sourceObj = window.convertToObj(sources)
mixpanel.track("Page View", sourceObj)
</script>
<!-- end Mixpanel -->
</head>
<body>
<div>
<div class="age-links">
<button onClick=redirectFunc(true)>YES</button>
<button onClick=redirectFunc(false)>NO</button>
</div>
</div>
</body>
</html>
js/scripts.js
(function() {
const convertToObj = () => ...
const getTrackingData = () => ...
const parseSourcesFromURL = () => ...
const redirectFunc = (p) => {
const { sources, link1, link2 } = parseSourcesFromURL(window.location.href)
const redirect = `${p ? link1 : link2}?${sources.join('&')}`
const mixpanelTrackingData = getTrackingData(sources, p, redirect)
mixpanel.track('Button Clicked', mixpanelTrackingData, () => {
window.location.href = redirect;
})
}
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined')
module.exports = {
....
};
else
window.utmSourcesToObject = utmSourcesToObject;
window.parseReferrerForLinksAndUTM = parseReferrerForLinksAndUTM;
window.redirectBasedOnAge = redirectBasedOnAge;
})();
js/scripts.test.js
const { redirectFunc, parseSourcesFromURL } = require('./js/scripts')
const testURL = 'https://test.com/'
describe('parseReferrerForLinksAndUTM', () => {
beforeEach(() => {
global.window = Object.create(window)
Object.defineProperty(window, 'location', {
value: { href: testURL },
writable: true
})
### THIS DOESNT WORK ###
Object.defineProperty(window, 'mixpanel', {
track: jest.fn()
})
})
const { sources, link1, link2 } = parseSourcesFromURL(testURL)
test('redirect link is correct', () => {
### THIS DOESNT WORK ###
global.mixpanel = Object.create({})
global.mixpanel.track = jest.fn()
expect(link1).toBe('https://link1.com')
})
})

.Vue component not refreshing on each new message in laravel

I followed the following tutorial to create a chat application.
https://github.com/ammezie/laravel-chat
Every thing is right, messages are storing in db , showing on console in pusher desktop, all message show on page re load.
Problem is when i send a new message it not show in other user tab until i reload the page. I need to make it dynamic
following is the code for app.js where fetch function is written
created() {
this.fetchMessages();
Echo.private('chat')
.listen('MessageSent', (e) => {
this.messages.push({
message: e.message.message,
user: e.user
});
});
},
methods: {
fetchMessages() {
axios.get('/messages').then(response => {
this.messages = response.data;
});
},
addMessage(message) {
this.messages.push(message);
axios.post('/messages', message).then(response => {});
}
here
Following is chat view code of component
<template>
<ul class="chat">
<li class="left clearfix" v-for="message in messages">
<div class="chat-body clearfix">
<div class="header">
<strong class="primary-font">
{{ message.user.name }}
</strong>
</div>
<p>
{{ message.message }}
</p>
</div>
</li>
</ul>
</template>
<script>
export default {
props: ['messages']
};
</script>
Thanks for help if some thing unclear i'll provide
You can try.
methods: {
var vm = this;
fetchMessages() {
axios.get('/messages').then(response => {
vm.messages = response.data;
});
},
addMessage(message) {
var vm = this;
vm.messages.push(message);
axios.post('/messages', message).then(response => {});
}
using this inside function causing a problem, because it refers to that particular function create a global variable with reference to this
Hope this helps.
You may want to check if there are Laravel Echo credentials for pusher correct in bootstrap.js

How to use List.JS with Vue + Axios?

I have used List.JS before successfully, but this time I'm trying to use it with a Vue.JS rendering of a list from JSON data.
I have a button at the top that when clicked should show only the QB position player.
Unfortunately I just get nothing, all list items are removed and I don't get an error in the console so I'm not sure how to diagnose this.
Could it have something to do with the fact that the list elements aren't prerendered/static html but injected using vue.js?
https://jsfiddle.net/nolaandy/hw2mheem/
HTML/Vue Template
<div id='app'>
<div class="all-players-wrapper" id="all-player-listings">
<button id="filter-qb">QB</button>
<ul class="list">
<li v-for="player in playerJSON">
<div class="player-listing">
<div class="player-left">
<div class="player-name">{{player.firstName}} {{player.lastName}}</div>
<div class="playerPosition">{{ player.Position }}</div>
</div><!-- end player-left -->
<div class="player-right">
<div class="player-grade">GRADE <span>{{player.NFLGrade}}</span></div>
</div> <!--end player-right -->
</div>
</li>
</ul>
</div>
</div>
JS
var vm = new Vue({
el: '#app',
data: {
status: 'Combine Particpants',
playerJSON: []
},
created: function () {
this.loadData();
},
methods: {
loadData: function () {
var self = this;
axios.get('https://s3-us-west-2.amazonaws.com/s.cdpn.io/500458/tiny.json').then(function (response) {
self.playerJSON = response.data
console.log(response.data);
})
.catch(function (error) {
self.status = 'An error occurred - ' + error
});
}
}
});
var options = {
valueNames: [ 'playerPosition' ]
};
var featureList = new List('all-player-listings', options);
$('#filter-qb').click(function() {
featureList.filter(function(item) {
if (item.values().playerPosition == "QB") {
return true;
} else {
return false;
}
});
return false;
});
As you suspected, List.js isn't going to work properly if the DOM changes unpredictably. In this case, axios makes its call and populates the data after the (empty) List has been read into featureList.
Your example would work if you put the list-selecting-and-filtering code in the resolution of the axios call, but that's not going to be a solution that works in a truly dynamic environment.
A custom directive will be called every time the DOM updates, so you can apply your adjustments consistently. Here's a directive to apply a filter using List.js:
directives: {
filteredList(el, binding) {
if (binding.value) {
const options = {
valueNames: ['playerPosition']
};
const featureList = new List(el, options);
featureList.filter((item) => item.values().playerPosition === binding.value);
}
}
}
Apply it like so:
<div class="all-players-wrapper" v-filtered-list="filterValue">
Add the filterValue data item, and have the button set it:
<button id="filter-qb" #click="() => filterValue='QB'">QB</button>
and you're in business.
It's worth noting that you could get the same effect by using a computed to filter the data, and you wouldn't need an external library.
Updated fiddle

Vuejs not updating list but updating obect

I am learning Vuejs and I am stuck. Why can I see the messages get added to the object (in Chrome Vue debugger) yet it is not added to the div that contains the list?
My Vue Component:
<template>
<div id="round-status-message" class="round-status-message">
<div class="row">
<div class="col-xs-12" v-for="sysmessage in sysmessages" v-html="sysmessage.message"></div>
</div>
</div>
</template>
<script>
export default {
props: ['sysmessages'],
methods: {
scrollToTop () {
this.$el.scrollTop = 0
}
}
};
</script>
My Vue instance:
$(document).ready(function()
{
Vue.component('chat-system', require('../components/chat-system.vue'));
var chatSystem = new Vue({
el: '#system-chat',
data: function () {
return {
sysmessages: []
};
},
created() {
this.fetchMessages();
Echo.private(sys_channel)
.listen('SystemMessageSent', (e) => {
this.sysmessages.unshift({
sysmessage: e.message.message,
});
this.processMessage(e);
});
},
methods: {
fetchMessages() {
axios.get(sys_get_route)
.then(response => {
this.sysmessages = response.data;
});
},
processMessage(message) {
this.$nextTick(() => {
this.$refs.sysmessages.scrollToTop();
});
// updateGame();
}
}
});
});
My template call in HTML:
<div id="system-chat">
<chat-system ref="sysmessages" v-on:systemmessagesent="processMessage" :sysmessages="sysmessages" :player="{{ Auth::user() }}"></chat-system>
</div>
There are no compile or run time errors and I can see records added to the props in the vue chrome tool. I can also see empty HTML elements added to the div.
What have I missed?
UPDATE: My record structures:
response.data is an array of objects, each like this:
{"data":[
{"id":100,
"progress_id":5,
"message":"start message",
"action":"welcome"
},
{"id"....
e.message.message contains the text message entry, so just a string.
I am trying to access the message variable in each object during the fetchMessages method.
You're adding objects with sysmessage as the property.
this.sysmessages.unshift({
sysmessage: e.message.message,
});
But you are trying to view
v-for="sysmessage in sysmessages" v-html="sysmessage.message"
Based on your update, the code should be:
this.sysmessages.unshift({
message: e.message.message,
});
And you can leave the template as
v-html="sysmessage.message"

Vue v-links in JSON data

I am relatively new to Vue, so forgive me if this is obvious (or obviously impossible).
I have a set of JSON data (fetched from a RESTful API via vue-resource):
{content: "This is content. <a href='/blog'> Link to blog </a>"}
Right now, the link triggers a page reload. If it were a vue-router v-link, that would not be an issue. However, this doesn't work (quotes are escaped in the data, of course):
{content: "This is content. <a v-link="{ path: '/blog' }"> Link to blog </a>"}
At this point, the template is already parsed, and Vue won't create a v-link anymore (it will just show up as a v-link in the rendered html).
My final result would ideally mean that I could include links in my CMS, either in HTML or Vue format, and have Vue route them correctly as v-links.
Is there something I can do to make Vue interpret the link in the JSON data?
I've answered the question on Vue Chat, and writing it here in case any other people facing similar problem
Simplified example on Codepen
HTML
<div id="app">
<div>
<a v-link= "{path:'/home'}">Go to home</a>
</div>
<router-view></router-view>
</div>
<template id="home">
<div>
<div>
Fetched Content:
</div>
<div>
{{{ fetchedContent }}}
</div>
</div>
</template>
<template id="route1">
<div>
Route1 view
</div>
</template>
<template id="route2">
<div>
Route2 view, this is different from Route1
</div>
</template>
javascript
function getContent (callback) {
var content = 'Click this: Go to route1 and Go to route2'
setTimeout(function () { callback(content) }, 1000)
}
var Home = Vue.component('home',{
template:'#home',
data: function () {
return {
fetchedContent: 'Loading...'
};
},
ready: function () {
var self = this
var router = this.$router
getContent( function (result) {
self.fetchedContent = result;
Vue.nextTick(function () {
var hyperLinks = self.$el.getElementsByTagName('a')
Array.prototype.forEach.call(hyperLinks, function (a) {
a.onclick = function (e) {
e.preventDefault()
router.go({ path: a.getAttribute("href") })
}
})
})
})
}
});
var Route1 = Vue.component('route1', {
template: '#route1'
});
var Route2 = Vue.component('route2', {
template: "#route2"
});
var router = new VueRouter({
hashbang:false,
history:true
});
router.map({
'/home':{
component:Home
},
'/route1':{
component:Route1
},
'/route2':{
component:Route2
}
});
router.start({
}, '#app');
I had a similar solution here: question using a custom dataset in my JSON code and a click listener to process it:
mounted() {
window.addEventListener('click', event => {
let target = event.target
if (target && target.href && target.dataset.url) {
event.preventDefault();
console.log(target.dataset.url);
const url = JSON.parse(target.dataset.url);
console.log(url.name)
this.$router.push(url.name);
}
});
},

Categories