Unexpected token when trying to subscribe - javascript

I am trying to understand Meteor.publish() and Meteor.subscribe(), with help from this video.
I have a collection defined like this:
export const Chansons = new Mongo.Collection('chansons');
Which I publish on my server:
Meteor.publish("chansons", function(){
return Chansons.find();
});
But then when I try to subscribe to it on my client, I have an error:
While building for web.browser:
imports/ui/body.js:17:14: Unexpected token, expected ";" (17:14)
What I do not get is that I wrote the code exactly like in the video, and it worked at first!
constructor() {
super();
this.state = {
subscription: {
chansons: Meteor.subscribe("chansons")
}
}
}
I then changed the formatting of my code somewhere else and now this error appeared and I cannot seem to fix it.
The error seems to come from the constructor(), since it goes away when I delete this block of code.
I know this question is really stupid, but I have no idea how to fix this.
edit: here is the whole body.js:
//Importation des méthodes
import { Template } from 'meteor/templating';
import { Meteor } from 'meteor/meteor';
import { Chansons } from '../api/chansons.js'
//Importation de body
import './body.html';
//Importation des templates
import './templates/header.html';
import './templates/youTube.html';
import './templates/search.html';
import './templates/parametres.html';
import './templates/affichagePlaylist.html';
//Subscription à la collection de chansons
constructor() {
super();
this.state = {
subscription: {
chansons: Meteor.subscribe("chansons")
}
}
}
//Lancement de YouTube
if (Meteor.isClient) {
onYouTubeIframeAPIReady = function() {
player = new YT.Player("player", {
//height: "400",
//width: "600",
videoId: "fkk1vg0nAfc",
events: {
onReady: function (event) {
event.target.playVideo();
}
}
});
};
YT.load();
};
Template.body.helpers({
chansons(){
return Chansons.find({})
}
});
Template.search.events({
'click #Ajouter' : function(){
const vidURL = document.getElementById("URL").value;
Chansons.insert({
URL : vidURL
});
const URLs = Chansons.find({},{ fields: { URL: 1, _id: 0 } }).map((chanson) => chanson.URL);
console.log(URLs);
}
});

Your statement with constructor() {} outside of a class declaration is invalid syntax.
You can declare a function using the short syntax version only within the scope of an object (or a class) in ES6. They are referred to as "methods" (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions)
With Meteor's Blaze frontend, you probably want to subscribe when the template instance is created, i.e.:
Template.body.onCreated(function () {
this.subscribe("chansons"); // Similar to Meteor.subscribe, but scoped to the template instance.
});

Related

How to call the function in a separate JS file through a vue instances [duplicate]

This question already has answers here:
"Uncaught SyntaxError: Cannot use import statement outside a module" when importing ECMAScript 6
(31 answers)
Closed 1 year ago.
I have a javascript function in a separate js file toaster-message.js, the file is in wwwroot/js of ASP.net application, which calls the bootstrap toaster.
toaster-message.js.
showCompleteToast: (message) => {
const toastElm = document.getElementById('#complete-toast');
const toast = new bootstrap.Toast(toastElm)
toast.show();
}
I want to call the showCompleteToast() from my vue instances. I am creating the vue instances with Direct script Include.
I don't want to add any Vue dependency to the function outside the Vue instances. So what is the proper way to call the function in the external js file that is outside the Vue instances?
#section scripts {
<script>
const app = new Vue({
el: "#app",
data() {
return {
}
},
methods: {
showToast: function(){
//I want to call the show toast from here
},
submit: async function () {
try {
this.showToast();
} catch (error) {
console.log(error)
}
}
}
});
</script>
}
When i try to import using:
import { showCompleteToast } from "~/lib/js/toater-message.js"
while using:
export default {
showCompleteToast: (message) => {
const toastElm = document.getElementById('#complete-toast');
const toast = new bootstrap.Toast(toastElm)
toast.show();
},
// ... other methods here
};
I get the error as:
“Uncaught SyntaxError: Cannot use import statement outside a module”
I tried to to import using:
<script type="module">
import { showCompleteToast } from "../../wwwroot/js/toaster-message.js"
alert(showCompleteToast)
</script>
This gave the error as:
GET https://localhost:44307/wwwroot/js/toaster-message.js net::ERR_ABORTED 404
I'm not very familiar with php but typically you can import JavaScript files and then work with their contents. The only requirement is that the imported files need to have exporting defined.
// toaster-message.js
export default {
showCompleteToast: (message) => {
const toastElm = document.getElementById('#complete-toast');
const toast = new bootstrap.Toast(toastElm)
toast.show();
},
// ... other methods here
};
Then pull it into your Vue file like this:
#section scripts {
<script>
import { showCompleteToast } from "..path/to/toaster-message.js"
const app = new Vue({
el: "#app",
data() {
return {
}
},
methods: {
showToast: function(){
//I want to call the show toast from here
showCompleteToast();
},
submit: async function () {
try {
this.showToast();
} catch (error) {
console.log(error)
}
}
}
});
</script>
}

Angular Document is not defined

I want to build my angular app for production using
npm run build:ssr
SSR is for server-side rendering.
But after build when I try to run my project it gives an error in my header components
Document is not defined
header.ts
mobileMenu() {
const mobileMenu = document.querySelector(".mobileHeader");
mobileMenu.classList.toggle("stickymobile");
const hambar = document.querySelector(".icon>i");
mobileMenu.classList.toggle("move");
const icon = document.querySelector(".icon");
icon.classList.toggle("open");
}
head() {
const image = document.querySelector(".image>img");
window.addEventListener("scroll", (e) => {
const header = document.querySelector(".desktopHeader");
if (window.pageYOffset > 25) {
header.classList.add("sticky");
//#ts-ignore
image.src = "../../../assets/Logo/Dark logo.svg";
} else {
header.classList.remove("sticky");
//#ts-ignore
image.src = "../../../assets/Logo/New logo.svg";
}
});
}
ngOnInit(): void {}
ngAfterViewInit(): void {
this.head();
}
How to resolve this error, please help
When you use Server side rendering you need to code being carefully with your code. Because some things changes when you code run in the server. Some of those things are the realted browser objects such as Document, window, etc and some functions such as SetTimeout and SetInterval. Those objects and functions does not exist in the server. So you need to avoid executon of some code when you are in the server and this is an example
import { Inject, PLATFORM_ID } from '#angular/core';
import { isPlatformBrowser } from '#angular/common';
constructor(#Inject(PLATFORM_ID) platformId: Object) {
this.isPlatFormBrowser = isPlatformBrowser(platformId);
}
mobileMenu() {
if(!this.isPlatFormBrowser) return;
// now when you are in the server this code does not be executed although in the browser it does
const mobileMenu = document.querySelector(".mobileHeader");
//rest of your code here...
}
head(){
if(!this.isPlatFormBrowser) return;
// now when you are in the server this code does not be executed although in the browser it does
window.addEventListener("scroll", (e) => {
//rest of your code here...
}

Having trouble working with data from component to component with Angular CLI

The main issue has something to do with the fact that I'm trying to have one component interact with another. I have a list of songs and the idea is that when one song is clicked it calls a function in the "now-playing-bar" component.
Just hitting the play/Pause button calls the playPause function and that works great. The issue comes from when you click a song on the "playlist" component and it calls the function playSong in the "now-playing-bar" component. The function itself seems to work fine, the song starts to play and the data values seem to be assigned. However two errors occur.
Error 1:
The html does not update to show the new title and artist.
Error 2:
When clicking play/pause to pause a song played from the "playlist" component, playPause function correctly outputs this with all it's correct data fields, but outputs undefined for this.playing
Code is abbreviated for easier reading
now-playing-bar.component.html
<div class="song">{{currentSong.title}}</div>
<div class="artist">{{currentSong.artist}}</div>
now-playing-bar.component.ts
export class NowPlayingBarComponent implements OnInit {
isActive: boolean;
progress: number = 10;
playing: boolean;
currentSong: Song = {
"id": null,
"title": "",
"artist": "",
"length": "",
"fileName": ""
};
song: any;
songs: Song[] = [];
constructor(private songService : SongsService) { }
ngOnInit() {
this.songService.fetchData()
.subscribe(d => this.songs = d as Song[]);
}
playPause() {
console.log('Play Pause this:');
console.log(this);
console.log(this.playing);
if (this.playing) {
console.log('Its playing');
this.playing = false;
this.song.pause();
}
else {
if (!this.song) {
this.song = new Howl({
src: ['assets/music/' + this.songs[0].fileName]
});
}
this.currentSong = this.songs[0];
this.playing = true;
this.song.play();
}
}
playSong(id: number) {
let that = this;
this.songService.fetchData()
.subscribe(function(d) {
if (that.playing) {
that.song.stop();
that.song.unload();
}
that.song = new Howl({
src: ['assets/music/' + d[id].fileName]
});
console.log(that.song)
console.log(that)
that.currentSong = d[id];
that.playing = true;
that.song.play();
});
}
}
playlist.component.ts
import { Component, OnInit } from '#angular/core';
import Song from "../models/Song"
import { SongsService } from "../songs.service";
import { NowPlayingBarComponent } from "../now-playing-bar/now-playing-bar.component"
export class PlaylistComponent implements OnInit {
songs: Song[] = [];
constructor(private songService : SongsService, private NP : NowPlayingBarComponent) { }
ngOnInit() {
this.songService.fetchData()
.subscribe(d => this.songs = d as Song[]);
}
songClicked(id) {
this.NP.playSong(id)
}
}
I'm happy to upload the full code if that would help, just didn't want to make it a cluttered mess. I've spent hours researching trying to figure this out but I just can't seem to get it. My best guess is the way that the "playlist" component is interacting with the "now-playing-bar" is incorrect.
Have implemented a working example # https://stackblitz.com/edit/component-to-component.
It uses two components Playlist and NowPlayingNavbar based on your example. I've also added a simulated SongService to emulated fetchData method.
Note: Avoid calling services from nested child components.
Have a look at Presentation vs Container components pattern in UI development.

Emitting global events from websocket listener

I want to contribute to a project - it's written in Vue, and I am a beginner in Vue.
I have two components - Setup and MainApp
Both will need to update some state based on different messages from the websocket. Some websocket messages will affect the former, some the latter.
Vue doesn't know services, so I thought I'd just create a custom component, with empty <template>. instantiate the websocket there and then issue an this.emit() every time a new message occurs in the listener.
Both other components would listen to the emits and would be able to react.
Unfortunately, I can't get the websocket component to work.
main.js:
import Ws from './WsService.vue';
//other imports
const routes = [
//routes
]
const router = new VueRouter({
routes // short for `routes: routes`
})
const app = new Vue({
router
}).$mount('#app')
//I thought this to be the way to instantiate my webSocket service:
const WsService = new Vue({
el: '#WsService',
components: { Ws }
});
index.html
<body>
<div id="app">
<div id="WsService"></div>
<router-link to="/setup">Setup</router-link>
<router-link to="/main-app">Main App</router-link>
<router-view></router-view>
</div>
<script src="/dist/demo-app.js"></script>
</body>
the websocket "service":
<template>
</template>
<script>
const PORT_LOCAL = 9988;
var ws = new WebSocket("ws://localhost:" + PORT_LOCAL);
ws.onopen = function() {
ws.send('{"jsonrpc":"2.0","id":"reg","method":"reg","params":null}');
};
ws.onerror = function(e) {
console.log("error in WebSocket connection!");
console.log(e);
};
export default {
data() {
return {
}
},
created() {
var self = this;
ws.onmessage = function(m) {
var msg = JSON.parse(m.data);
switch(msg.id) {
// result for address request
case "reg":
self.$emit("reg_received", msg.result);
break;
case "send":
self.$emit("send_received", msg.result);
break;
case "subscribe":
self.$emit("subscribe_received", msg.result);
break;
default:
console.log(msg);
break;
}
}
},
methods: {
},
send(id, method, params) {
ws.send('{"jsonrpc":"2.0","id":"' + id + '","method":"' + method + '","params":null}');
}
}
}
</script>
Send for example from main app (this seems to work):
import WsSvc from './WsService.vue';
export default {
data() {
//
},
subscribe() {
let jsonrpc = "the jsonrpc string";
WsSvc.send(jsonrpc);
}
}
Listening to emit:
export default {
data() {
//
},
created() {
this.$on("reg_received", function(result){
//do smth with the result
});
}
}
Wit this configuration, the created hook actually never gets called - and thus I'll never hit the onmessage listener. The reason to have a custom component I thought was that I would have access to the emit function.
It feels I am making it more complicated than it should be but I haven't managed yet to get it right. The solution doesn't need to follow this approach.
There's no need for a socket specific component in this case. What I have done in the past on a couple projects is implement an API or store object that handles the socket messages and then import that API or store into the components that need it. Also in a similar answer, I show how to integrate a WebSocket with Vuex.
Here is an example that combines the concept of using Vue as an event emitter with a web socket that can be imported into any component. The component can subscribe and listen to the messages it wants to listen to. Wrapping the socket in this way abstracts the raw socket interface away and allows users to work with $on/$off subscriptions in a more typically Vue fashion.
Socket.js
import Vue from "vue"
const socket = new WebSocket("wss://echo.websocket.org")
const emitter = new Vue({
methods:{
send(message){
if (1 === socket.readyState)
socket.send(message)
}
}
})
socket.onmessage = function(msg){
emitter.$emit("message", msg.data)
}
socket.onerror = function(err){
emitter.$emit("error", err)
}
export default emitter
Here is an example of that code being used in a component.
App.vue
<template>
<ul>
<li v-for="message in messages">
{{message}}
</li>
</ul>
</template>
<script>
import Socket from "./socket"
export default {
name: 'app',
data(){
return {
messages: []
}
},
methods:{
handleMessage(msg){
this.messages.push(msg)
}
},
created(){
Socket.$on("message", this.handleMessage)
},
beforeDestroy(){
Socket.$off("message", this.handleMessage)
}
}
</script>
And here is a working example.
Hey this should work for you better and easy
This my example with .vue file
yourVueFile.Vue
<template>
// key in your template here
</template>
<script>
export default {
//use the created() option to execute after vue instance is created
created() {
let ws = new WebSocket("yourUrl");
ws.onopen = e => {
ws.send(
JSON.stringify({ your json code })
);
ws.onmessage = e => {
let data = JSON.parse(e.data);
// the this.$data get your data() options in your vue instance
this.$data.dom = data;
};
};
},
data() {
return {
dom: core
};
},
methods: {
}
};
</script>

Javascript ServiceStack Client serialization error

So I have a master/detail scenario between two views. The master page shows a list and after clicking on one of the items, I send a message via the EventAggregator in Aurelia to the child view with a deserialized dto (coming from the selected item of the master) as a payload of the message.
However when I then try to pass this item as a parameter of a subsequent request in the child (to get additional info) the payload object fails to serialize.
Master.ts:
import { JsonServiceClient } from "servicestack-client";
import {
ListPendingHoldingsFiles,
ListPendingHoldingsFilesResponse,
SendHoldings,
PositionFileInfo
} from "../holdingsManager.dtos";
import { inject, singleton } from "aurelia-framework";
import { Router } from "aurelia-router";
import { EventAggregator } from "aurelia-event-aggregator";
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage";
#singleton()
#inject(Router, EventAggregator)
export class Pending {
router: Router;
positions: PositionFileInfo[];
client: JsonServiceClient;
eventAgg: EventAggregator;
constructor(router, eventAggregator) {
this.router = router;
this.eventAgg = eventAggregator;
this.client = new JsonServiceClient('/');
var req = new ListPendingHoldingsFiles();
this.client.get(req).then((getHoldingsResponse) => {
this.positions = getHoldingsResponse.PositionFiles;
}).catch(e => {
console.log(e); // "oh, no!"
});
}
openHoldings(positionInfo) {
this.eventAgg.publish(new GetPendingPositionMessage(positionInfo));
this.router.navigate('#/holdings');
}
}
Child.ts:
import { JsonServiceClient } from "servicestack-client";
import { inject, singleton } from "aurelia-framework";
import { Router } from 'aurelia-router';
import { EventAggregator } from "aurelia-event-aggregator";
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage";
import {
GetPendingHoldingsFile,
GetPendingHoldingsFileResponse,
Position,
PositionFileInfo
} from "../holdingsManager.dtos";
#singleton()
#inject(Router, EventAggregator)
export class Holdings {
router: Router;
pendingPositionFileInfo: PositionFileInfo;
position: Position;
client: JsonServiceClient;
eventAgg: EventAggregator;
constructor(router, eventAggregator) {
this.router = router;
this.eventAgg = eventAggregator;
this.eventAgg.subscribe(GetPendingPositionMessage,
message => {
this.pendingPositionFileInfo = message.fileInfo;
});
}
activate(params, routeData) {
this.client = new JsonServiceClient('/');
var req = new GetPendingHoldingsFile();
req.PositionToRetrieve = this.pendingPositionFileInfo;
this.client.get(req).then((getHoldingsResponse) => {
this.position = getHoldingsResponse.PendingPosition;
}).catch(e => {
console.log(e); // "oh, no!"
});
}
}
So the error happens when the child activates and attempts to send the request 'GetPendingHoldingsFile'.
Failed to load resource: the server responded with a status of 500 (NullReferenceException)
I have verified that this.pendingPositionFileInfo in the child is not null or empty and that on the server side, the object is not being received (it is null). I am new to Aurelia and not very experienced with Javascript so I must be missing something, any advice would be appreciated.
Edit 1
This seems to be something wrong with how I'm interacting with ServiceStack. I'm using version 4.5.6 of serviceStack with servicestack-client#^0.0.17. I tried newing up a fresh copy of the dto (PositionFileInfo) and copying over all the values from the parent view just to be sure there wasn't some javascript type conversion weirdness happening that I'm not aware of, but even with a fresh dto the webservice still receives a null request.
Switching from 'client.get(...)' to 'client.post(...)' fixed the problem. Apparently trying to serialize the object over in the URL was not a good plan.

Categories

Resources