How to use luxon in vue3 - vue.js

I want to use luxon in my vue 3 application (https://moment.github.io/luxon/#/)
But unfortunately it is not supporting vue3 right now. Thats why I want to wrap my application with luxon but I dont know how to do it exactly.
So in my component I imported luxon like this:
import { DateTime } from 'luxon';
methods: {
getCurrentMonth() {
const currentMonth = DateTime().month() + 1;
return currentMonth;
}
}
But I am getting an error like this: Uncaught (in promise) TypeError: Class constructor DateTime cannot be invoked without 'new'
I think that because I am using/wrapping luxon wrong in my vue3 application.
How can I fix it?

You cannot use DateTime() without new keyword (and config parameter, see docs).
I suggest to use DateTime.now() to get the current date and time. Moreover, month is a member of DateTime object not a method.
Your code could be like the following:
import { DateTime } from 'luxon';
methods: {
getCurrentMonth() {
const currentMonth = DateTime.now().month + 1;
return currentMonth;
}
}

Related

Using refs with Vue 3 + TypeScript + Options API

I am trying to understand the best way to use refs together with TypeScript and the Options API. In the docs they reference it like below, but that is without using TS. When it comes to TS, they only explain how to use it with Composition API.
When I use this.$refs.myRef it throws this error Object is of type 'unknown'.
I know that I can cast it and use it like this: (this.$refs.myRef as HTMLElement) but that I feel shouldn't be necessary to do for every ref every single time.
What is the correct way to use a reference with Options API + TS?
I created a shim like this:
shims-runtime-core.d.ts
import * as runtimeCore from '#vue/runtime-core'
declare module '#vue/runtime-core' {
interface ComponentCustomProperties {
$refs: {
[key: string]: HTMLElement|any,
},
// ... more stuff
}
}
And then I can access the refs like normal.

VueJs - using template strings inside the data function returns undefined

When I'm trying to use Template strings inside the data function in vuejs but, it always returns undefined any idea how to solve this ?
I was trying to make a URL for an API call dynamic
Cheers,
data() {
return {
baseUrl: `https://example.com/api/json?key=${this.key}`,
key: "IzNDU2Nzg5MDEyMzQ1Njc"
};
}
This is a JavaScript issue. If you run the following simple example in JavaScript you'll get a "is not defined" error (when running in strict mode).
{ a: `${b}`, b: "123" }
> VM246:1 Uncaught ReferenceError: b is not defined
You can't reference an adjacent variable ('key' in your example) in an object literal declaration.
You can use a Vue.je computed property for baseURL:
computed: {
baseUrl() {
return `https://example.com/api/json?key=${this.key}`;
}
}
The data property cannot be made dynamic. Use a computed property like below:
computed: {
baseUrl() {
return `https://example.com/api/json?key=${this.key}`
}
}

GraphQL gql Syntax Error: Expected Name, found }

I'm attempting to set up Apollo GraphQL support in a new React project, but when I try to compile a query using gql I keep receiving the error:
Syntax Error: Expected Name, found }
This is generated by the following code:
import gql from 'graphql-tag'
const query = gql`
{
user(id: 5) {
firstName
lastName
}
}
`
console.log(query)
I'm basing this code off the example code found here: https://github.com/apollographql/graphql-tag
What is the Name referred to in the error message? Does anyone know what I'm doing wrong here?
This error occurs mostly when there are unclosed curly braces or when some fields are not properly defined while calling the query.
The accepted answer didn't solve my issue. Instead, it worked if you remove the initial curly brackets.
The query should look like this instead:
const query=gql`
user(id: 5) {
firstName
lastName
}
`
The causes could be:
you are adding a "()" at the beginning for no reason
you need to add more 'nested' parameters.
Especially if you are using an online GraphiQL editor. Examples:
1- Wrong code (extra parenthesis)
{
allFilms() {
films {
title
}
}
}
2- Wrong code (more parameters need it eg: title)
{
allFilms {
films {
}
}
}
3- Correct code
{
allFilms {
films {
title
}
}
}
GraphQLError: Syntax Error: Expected Name, found "$".
One more example of a similar error (For other users).
theErrorIsHere (Could be extra ( or { before the $varName) added before $speakerId
Error code:
const FEATURED_SPEAKER = gql`
mutation markFeatured($speakerId: ID!, $featured: Boolean!){
markFeatured(speaker_id: theErrorIsHere$speakerId , featured: $featured){
id
featured
}
}
`;
Correct code:
const FEATURED_SPEAKER = gql`
mutation markFeatured($speakerId: ID!, $featured: Boolean!){
markFeatured(speaker_id: $speakerId , featured: $featured){
id
featured
}
}
`;
I'm not 100% sure what the root of my problem was, but moving all the query code into a separate es6 module fixed the issue. There must have been some kind of contamination from the surrounding code. For reference my query was embedded within a React component.
This works:
import gql from 'graphql-tag'
const query = gql`
{
user(id: 5) {
firstName
lastName
}
}
`
export default query
Another cause for this error: you are referencing a type that is defined further down. Move the type you are referencing up.
For example:
type Launch {
rocket: Rocket
}
type Rocket {
name: String
}
will throw an error, as Launch references Rocket before Rocket is defined.
The corrected code:
type Rocket {
name: String
}
type Launch {
rocket: Rocket
}
In my case, I got the error simply because I'm adding : which I shouldn't have done.
e.g:
const query = `
query($id: String!) {
getUser(id: $id) {
user: {
id
name
email
createdAt
}
}
}
`
If you pay close attention to line 4 of the code above you'll realize that I added : after the user before the curly brace, then I began to list the user's data I wanna query and THAT WAS EXACTLY WHERE THE ERROR WAS!
Removing the : solve the issue!
It should be:
user {
id
name
...
}
In NestJS framework, this error happened to me because I defiled GraphQL field in my schema.graphql file as:
lastUpdated(): Date
Instead it should be just
lastUpdated: Date
(it doesn't take any argument)
I was receiving a similar error server side:
GraphQLError: Syntax Error: Expected Name, found ]
I realized the cause in my case was a type definition with an empty array.
This breaks:
type Settings {
requires: []
}
But this works:
type Settings {
requires: [String]
}
I had this problem and the cause was a string value with double-quotes inside double-quotes, like so: "this "is" bad".
In my case I got the error because of the following:
const GET_POSTS_OF_AUTHOR = gql`
query GetPostsOfAuthor($authorId: Int!) {
postsOf($authorId: Int!) {
id
title
}
}
`;
When it should have been:
const GET_POSTS_OF_AUTHOR = gql`
query GetPostsOfAuthor($authorId: Int!) {
postsOf(authorId: $authorId) {
id
title
}
}
`;
erroneously thought $authorId passed through identically to the function call instead of setting a property inside the function call.
This can happen if you use gql from #clinet/apollo and in the backticks you try to inject dynamic js value. Remove it and replace with normal scalar and it will fix your issue.
example:
${SOME_MAX_VALUE} -> 20
On ny side the error was caused by extra {} Curly braces. Solved by just removing them.
I was getting the same error. In my case putting the id inside double quote solved the issue as the type of id required string value.
{
product(id: "${id}") {
name
}
}
Posting here in case anyone else had this problem but you also get this error if you accidentally make your query look like json with colons (:).
ex:
data {
property {
key: {
deepKey
}
}
}
will give the same error from GQL compile

pass data to another route without messing with url

DISCLAIMER: I'm a noob.. sorry
Say I have 2 different components that are siblings:
comp1 and comp2
I wish to route from comp1 to comp2 with a bunch of data. How can I achieve this without getting a fugly url-bar containing everything?
I've tried using a separate class, lets call it DataTransmitter:
data-transmitter.js:
export class DataTransmitter {
constructor() {
this.val= "a";
}
}
comp1.js:
import { DataTransmitter } from './data-transmitter';
#inject(DataTransmitter)
export class comp1{
constructor(DataTransmitter){
this.DataTransmitter = DataTransmitter;
}
someMethod(){
this.DataTransmitter.val = "b";
console.log('comp1: ' + this.DataTransmitter.val);
}
}
comp2.js:
import { DataTransmitter } from './data-transmitter';
#inject(DataTransmitter)
export class comp2{
constructor(DataTransmitter){
this.DataTransmitter = DataTransmitter;
}
someMethod(){
console.log('comp2: ' + this.DataTransmitter.val);
}
}
This gives me the output:
comp1: b
comp2: a
I've also tried messing around with EventAggregator, but no success.
Is there some way of routing with parameters WITHOUT having a url that looks like site/comp2?data=stuff&things=otherstuff&params=values&more=etc?
You absolutely want to use a singleton class and then inject it inside of whatever components you need your data. The link that Gaby posted is definitely what you want to do.
The reason your posted code does not work is because you're attempting to use the inject decorator, but you're not importing it. Please see this working example of what you are trying to do on Gist.run here. I have two components, you can click to route between them and set the value. You'll notice the set value remains when you navigate back and forth.

Aurelia: Update the custom element on changes to the bound object

I have a custom element called summary-bar with summary property:
export class SummaryBarCustomElement {
#bindable summary;
---
In another component test-website, I uses the summary-bar element and bind its data as below:
<summary-bar summary.bind="testWebsiteSummary"></summary-bar>
And here testWebsiteSummary is defined in the test-website.js ViewModel:
export class TestWebsiteCustomElement {
testWebsiteSummary = {
passed_result_count: 0,
failed_result_count: 0,
incomplete_result_count: 0,
unknown_result_count: 0
}
---
There are several functions in TestWebsiteCustomElement class that modify the values of testWebsiteSummary.passed_result_count, testWebsiteSummary.failed_result_count, testWebsiteSummary.incomplete_result_count and testWebsiteSummary.unknown_result_count. However, the summary-bar element is not reloaded with the new values of testWebsiteSummary. Is there a way to achieve that? What I mean is every time the properties of testWebsiteSummary is updated, is it possible to update the summary-bar with the new values? Thank you.
Example of a function which changes the properties:
changeWebsiteSummary(status) {
switch (status) {
case "SUCCESS":
this.testWebsiteSummary.passed_result_count++;
this.testWebsiteSummary.incomplete_result_count--;
break;
case "INCOMPLETE":
this.testWebsiteSummary.incomplete_result_count++;
this.testWebsiteSummary.passed_result_count--;
break;
default:
}
}
When you bind an object into your Custom Element it will update its values automatically. Whenever your TestWebsiteCustomElement changes any of the properties in testWebsiteSummary, those changes will be automatically reflected in your SummaryBarCustomElement. That is, if you are for example displaying testWebsiteSummary.passed_result_count in the SummaryBarCustomElement view, then it will be automatically updated in the ui.
Now, if what you want is to know when those changes occur to do something else, then you need to use a propertyObserver.
Aurelia by default support adding methods such as summaryChanged(newValue, oldValue) to custom elements. This works just fine for primitive values, but for Objects (or arrays) this method will not be triggered if any of the internal properties changes, only if the object itself has been reassigned.
To work around this you can use the binding engine to observe specific properties inside your summary object. Here is what it would look like:
import {bindable, BindingEngine, inject} from 'aurelia-framework';
#inject(BindingEngine)
export class SummaryBarCustomElement {
#bindable summary;
constructor(bindingEngine){
this.bindingEngine = bindingEngine;
}
bind(){
this.subscription = this.bindingEngine.propertyObserver(this.summary, 'passed_result_count')
.subscribe(newValue, oldValue => this.passedResultCountChanged(newValue, oldValue))
}
detached(){
this.subscription.dispose();
}
passedResultCountChanged(newValue, oldValue){
//Do something
}
}
You can use the signal binding behaviour
<summary-bar summary.bind="testWebsiteSummary & signal:'your-signal'"></summary-bar>
And the class:
import {BindingSignaler} from 'aurelia-templating-resources';
export class TestWebsiteCustomElement {
constructor(signaler: BindingSignaler) {
this.signaler = signaler;
}
functionThatChangesValues(){
this.signaler.signal('your-signal');
}
}