link137 link138 link139 link140 link141 link142 link143 link144 link145 link146 link147 link148 link149 link150 link151 link152 link153 link154 link155 link156 link157 link158 link159 link160 link161 link162 link163 link164 link165 link166 link167 link168 link169 link170 link171 link172 link173 link174 link175 link176 link177 link178 link179 link180 link181 link182 link183 link184 link185 link186 link187 link188 link189 link190 link191 link192 link193 link194 link195 link196 link197 link198 link199 link200 link201 link202 link203 link204 link205 link206 link207 link208 link209 link210 link211 link212 link213 link214 link215 link216 link217 link218 link219 link220 link221 link222 link223 link224 link225 link226 link227 link228 link229 link230 link231 link232 link233 link234 link235 link236 link237 link238 link239 link240 link241 link242 link243 link244 link245 link246 link247 link248 link249 link250 link251 link252 link253 link254 link255 link256 link257 link258 link259 link260 link261 link262 link263 link264 link265 link266 link267 link268 link269 link270 link271 link272 link273

[Vue.js] Fixed element in a vuetify.js v-sheet does not work Subscribe to RSS

when developing a site with vuetify. there is this layout:

The problem is that I used display absolute in the copy-code icon, so if I scroll to the right the code, I get this:

If I try to set display from absolute to fixed, I do not know why, I find the icon no more in the code snippet but in the top-right corner of the page:

This is the code of the most inner component (the code snippet):

<template>
<div>
<v-fade-transition>
<v-sheet class=”code d-flex grey–text text–lighten-3 pa-4” :color=”background” @mouseenter=”showCopy = true” @mouseleave=”showCopy = false”>
<v-fade-transition>
<v-btn v-if=”showCopy” flat icon class=”copy” color=”success lighten-3” @click=”copyCode”>
<v-icon>content_copy</v-icon>
</v-btn>
</v-fade-transition>

<v-layout column>
<v-flex
v-for=”(row, index) of rows”
:key=”index”
:class=”getClass(index)”
@mouseenter=”rowEntered(index)”
@mouseleave=”rowLeft(index)”
@click=”rowClicked(index)”
\>
<span class=”orange–text text–lighten-3 mr-3 code-row”>{ getRowText(index + 1) }</span>
<span>{ row }</span>
</v-flex>
</v-layout>
</v-sheet>
</v-fade-transition>

<v-snackbar v-model=”showSnackbar” color=”success”>
<span>Testo copiato negli appunti!!!</span>
<v-btn dark flat @click=”showSnackbar = false”>Close</v-btn>
</v-snackbar>
</div>
</template>

<script lang=”ts”>
import vue.js from ‘vue’;
import { Component, Prop } from ‘vue-property-decorator’;
import copyToClipboard from ‘copy-to-clipboard’;

@Component({
components: {}
})
export default class AppExamCardCode extends vue.js {
@Prop({ type: String, required: true })
readonly code!: string;

readonly color = ‘grey’;
readonly darkenDefault = ‘darken-3’;
readonly darkenSelected = ‘darken-2’;
showCopy = false;
showSnackbar = false;
hovered = -1;
selected: number[] = [];

get background(): string {
return this.color + ‘ ‘ + this.darkenDefault;
}

get rows(): string[] {
return this.code.split(‘\n’);
}

//rowClicked, rowLeft, rowEntered, getClass(returns only row background color, getRowText),

copyCode(): void {
copyToClipboard(this.code);
this.showSnackbar = true;
}
}
</script>

<style scoped>
.code {
border-radius: 12px;
overflow-x: auto;
letter-spacing: 0.5px;
word-spacing: 1px;
font-family: “Inconsolata”, monospace;
white-space: pre;
font-weight: 300;
font-size: 15px;
}

.code-row {
letter-spacing: 0.8px;
}

.copy {
position: absolute;
top: 0;
right: 0;
margin: 5px;
}
</style>

This is where it is contained: (AppExamCardCodeExercise)

<template>
<div class=”code-exercise”>
<app-exam-card-code :code=”exercise.code” />
<app-exam-card-code-answer :solution=”exercise.solution” :showAnswers=”showAnswers”/>
</div>
</template>

Contained in AppExamCardExercise:

<template>
<div>
<app-exam-card-true-or-false-exercise v-if=”isTrueOrFalse” :showAnswers=”showAnswers”/>
<app-exam-card-code-exercise v-else :showAnswers=”showAnswers”/>
</div>
</template>

Contained in AppExamCard:

<template>
<div>
<v-scale-transition>
<v-card v-if=”show” class=”exam-card” :class=”cardClass” flat>
<!– omitted –>
</v-toolbar>

<v-card-text>
<v-slide-y-transition mode=”out-in”>
<v-layout row pa-5 :key=”current”>
<v-flex xs12>
<app-exam-card-score v-if=”isFinished && showScore” />
<app-exam-card-exercise v-else :showAnswers=”showAnswers” />
</v-flex>
</v-layout>
</v-slide-y-transition>
</v-card-text>

<v-card-actions>
<!– omitted –>
</v-card-actions>
</v-card>
</v-scale-transition>
</div>
</template>

Solution :

the problem is that the copy icon is position: absolute and the code block (with the scrollbar) is position: relative, so it scrolls together.

Set the code block to position: static and then wrap it in a div and set that div to position: relative, so the copy-button is relative to the parent-parent div (which is not scrollable)

HTML

<div class=”fix”>
<code>
<span class=”copy”>Copy</span>
[…]
</code>
</div>

CSS

.fix {
position: relative;
}
.fix code {
position: static;
}

See: https://jsfiddle.net/voxp8rgf/1/

[Vue.js] How do I properly mock a DOM so that I can test a Vue app with Jest that uses Xterm.js? Subscribe to RSS

there is a vue.js component that renders an Xterm.js terminal.

Terminal.vue

<template>
<div id=”terminal”></div>
</template>

<script>
import vue.js from ‘vue’;
import { Terminal } from ‘xterm/lib/public/Terminal’;
import { ITerminalOptions, ITheme } from ‘xterm’;

export default Vue.extend({
data() {
return {};
},
mounted() {
Terminal.applyAddon(fit);
this.term = new Terminal(opts);
this.term.open(document.getElementById(‘terminal’));
},
</script>

I would like to test this component.

Terminal.test.js

import Terminal from ‘components/Terminal’
import { mount } from ‘@vue/test-utils’;

describe(‘test’, ()=>{
const wrapper = mount(App);
});

When I run jest on this test file, I get this error:

TypeError: Cannot set property ‘globalCompositeOperation’ of null

45 | this.term = new Terminal(opts);
\> 46 | this.term.open(document.getElementById(‘terminal’));

Digging into the stack trace, I can see it has something to do with Xterm’s ColorManager.

at new ColorManager (node_modules/xterm/src/renderer/ColorManager.ts:94:39)
at new Renderer (node_modules/xterm/src/renderer/Renderer.ts:41:25)

If I look at their code, I can see a relatively confusing thing:

xterm.js/ColorManager.ts

constructor(document: Document, public allowTransparency: boolean) {
const canvas = document.createElement(‘canvas’);
canvas.width = 1;
canvas.height = 1;
const ctx = canvas.getContext(‘2d’);
// I would expect to see the “could not get rendering context”
// error, as “ctx” shows up as “null” later, guessing from the
// error that Jest caught
if (!ctx) {
throw new Error(‘Could not get rendering context’);
}
this._ctx = ctx;
// Somehow this._ctx is null here, but passed a boolean check earlier?
this._ctx.globalCompositeOperation = ‘copy’;
this._litmusColor = this._ctx.createLinearGradient(0, 0, 1, 1);
this.colors = {
foreground: DEFAULT_FOREGROUND,
background: DEFAULT_BACKGROUND,
cursor: DEFAULT_CURSOR,
cursorAccent: DEFAULT_CURSOR_ACCENT,
selection: DEFAULT_SELECTION,
ansi: DEFAULT_ANSI_COLORS.slice()
};
}

I’m not quite clear on how canvas.getContext apparently returned something that passed the boolean check (at if(!ctx)) but then later caused a cannot set globalCompositeOperation of null error on that same variable.

I’m very confused about how I can successfully go about mock-rendering and thus testing this component - in xterm’s own testing files, they appear to be creating a fake DOM using jsdom:

xterm.js/ColorManager.test.ts

beforeEach(() => {
dom = new jsdom.JSDOM(‘’);
window = dom.window;
document = window.document;
(<any>window).HTMLCanvasElement.prototype.getContext = () => ({
createLinearGradient(): any {
return null;
},

fillRect(): void { },

getImageData(): any {
return {data: [0, 0, 0, 0xFF]};
}
});
cm = new ColorManager(document, false);
});

But I believe that under the hood, vue-test-utils is also creating a fake DOM using jsdom. Furthermore, the documentation indicates that the mount function both attaches and renders the vue.js component.

Creates a Wrapper that contains the mounted and rendered vue.js component.

https://vue-test-utils.vuejs.org/api/#mount

How can I successfully mock a DOM in such a way that I can test a vue.js component that implements Xterm.js, using Jest?

Solution :

There are multiple reasons for this.

First of all, Jest js uses jsdom under the hood, as I suspected.

Jsdom doesn’t support the canvas DOM api out of the box. First of all, you need jest-canvas-mock.

npm install –save-dev jest-canvas-mock

Then, you need to add it to the setupFiles portion of the jest config. Mine was in package.json, so I added it like so:

package.json

{
“jest”: {
“setupFiles”: [“jest-canvas-mock”]
}
}

Then, I was getting errors about the insertAdjacentElement DOM element method. Specifically, the error was:

[vue.js warn]: Error in mounted hook: “TypeError: _this._terminal.element.insertAdjacentElement is not a function”

This is because the version of jsdom used by jest is, as of today, 11.12.0 :

npm ls jsdom

jest@24.8.0
jest-cli@24.8.0
jest-config@24.8.0
jest-environment-jsdom@24.8.0
jsdom@11.12.0

Through the help of stackoverflow, I discovered that at version 11.12.0, jsdom had not implemented insertAdjacentElement. However, a more recent version of jsdom implemented insertAdjacentElement back in July of 2018.

Efforts to convince the jest team to use a more up to date version of jsdom have failed. They are unwilling to let go of node6 compatibility until the absolute last second (they claimed back in April), or alternatively don’t want to implement jsdom at all anymore, and are recommending people fork their own versions of the repo if they want the feature.

Luckily, you can manually set which version of jsdom jest uses.

First, install the jest-environment-jsdom-fourteen package.

npm install –save jest-environment-jsdom-fourteen

Then, you need to modify the testEnvironment property of the jest config. So, now my jest config looks like:

package.json

“jest”: {
“testEnvironment”: “jest-environment-jsdom-fourteen”,
“setupFiles”: [“jest-canvas-mock”]
}

Now, I can run tests without errors.

[Vue.js] Using LocalStorage in JS using vue.js and having a complex set of objects Subscribe to RSS

I use vue.js, there is a JSON called projects wich will have inside an array of the object Teams and each Team will have an array of objects User.

Like this: https://project1-e5692.firebaseapp.com/

I can’t figured out how to save a new team or a new user succefully on that Json, I can already Load the main JSON, do something with it and then save that main JSON again.

saveteam() {
project = JSON.parse(localStorage.getItem(‘projects’));
var user1 = {“name”:”user1”}; //To test if a user gets pushed in a team

team.push(user1);
team.teamname=this.teamname; //What I get from the HTML
projects.push(team); //Trying to push the team (Wish has the user inside already) on the current project
console.log(projects);
console.log(project);
project.push(projects); //then I push a new project inside the projects array
localStorage.setItem(“projects”,JSON.stringify(project)); // then I save the JSON back
}

Solution :

saveteam() {
let projects = JSON.parse(localStorage.getItem(‘projects’));
let project = {};
let team = {};
let user1 = {“name”:”user1”};

team.push(user1);
project.push(team);
projects.push(project);
localStorage.setItem(“projects”,JSON.stringify(projects));
},

[Vue.js] Bundle styles in Vue Plugin without Component Subscribe to RSS

My Question

Before reading further, by ‘without component’, I mean that my plugin does not require a component as there is no template, it is simply a custom vue.js Directive that serves as a wrapper to a class. However, that does not mean that when not willing to use a component in order to include the necessary styles if this cannot be avoided…

Consider the following plugin (proposed file structure):

src
index.js
SomeClass.js

sass // (not sure about this)
core.scss

index.js installs the vue.js plugin and defines a custom directive that calls certain methods on the SomeClass class
SomeClass.js provides all required functionality
sass/core.scss provides any necessary styles required for the plugin

My question, quite simply, is how do I include the core.scss file when the vue.js plugin is installed? Or, what would be a better file structure, thus way to include the styles required for the plugin?

Ideally, I would like to avoid using a template as there is no HTML inserted, my plugin simply adds styles to already defined elements in the DOM.

Solution :

For anyone stumbling upon this, the solution was extremely easy… I simply placed the following at the top of my index.js:

import ‘./sass/_core.scss’;

I wasn’t aware that you could import CSS/SASS files directly into Javascript files…

[Vue.js] Add class on click at a specific item in a grid in Vue Subscribe to RSS

there is a grid of items (created in flexbox so as to use v-for loops).
I would like to add class .selected on click on a specific item in a list.
There’s a problem that item in every column gets class that should be applied only to a single element. What should I do to make it work?

Grid:

new Vue({
el: “#app”,
data: {
rows: 8,
items: [
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
}
]
}
})
.app > ul {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 4vh;
padding-bottom: 4vh;
border-bottom: 1px solid gray;
}
.app > ul > li.row > ul {
display: flex;
margin: 8px 0;
}
.app > ul > li.row > ul li {
width: 36px;
height: 36px;
border-radius: 50%;
background-color: transparent;
border: 3px solid gray;
margin: 0 8px;
}
.app > ul > li.row > ul li.selected {
background-color: gray;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
}
<script src=”https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id=”app” class=”app”>
<ul>
<li v-for=”row in rows” class=”row”>
<ul>
<li v-for=”item, index in items” :key=”index” :class=”{ selected: item.selected }” @click=”item.selected = !item.selected”></li>
</ul>
</li>
</ul>
</div>

Solution :

You’re thinking along the right lines. It’s the data structure that’s the problem.

You only have 7 items - but you’re expecting them to behave like 8 rows of 7 items. the data object should reflect the structure you are looping in the DOM.

Something like this would be what you are after:

new Vue({
el: “#app”,
data: {
rows: [
{
items: [
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
}
]
},
{
items: [
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
}
]
},
{
items: [
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
}
]
},
{
items: [
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
}
]
},
{
items: [
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
}
]
},
{
items: [
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
}
]
},
{
items: [
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
}
]
},
{
items: [
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
},
{
selected: false
}
]
}
]

}
})
.app > ul {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 4vh;
padding-bottom: 4vh;
border-bottom: 1px solid gray;
}
.app > ul > li.row > ul {
display: flex;
margin: 8px 0;
}
.app > ul > li.row > ul li {
width: 36px;
height: 36px;
border-radius: 50%;
background-color: transparent;
border: 3px solid gray;
margin: 0 8px;
}
.app > ul > li.row > ul li.selected {
background-color: gray;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
}
<script src=”https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id=”app” class=”app”>
<ul>
<li v-for=”(row, rowIndex) in rows” class=”row”>
<ul>
<li v-for=”(item, index) in row.items” :key=”index + ‘_‘ + rowIndex” :class=”{ selected: item.selected }” @click=”item.selected = !item.selected”></li>
</ul>
</li>
</ul>
</div>

Edit: you don’t have to hard code those values. You could, if you chose, generate them in a loop on component mounted() (or other suitable event) using Vue.$set().

An example of using Vue.$set() in a mounted() hook, within the component:

export default {
mounted () {
const rows = 8
const itemsPerRow = 7

for (let r = 0; r < rows; r++) {
let row = {
items: []
}

for (let i = 0; i < itemsPerRow; i++) {
row.items.push({
selected: false
})
}

this.$set(this.rows, r, row)

}
},

data () {
return {
rows: []
}
}
}

[Vue.js] $.parent vs emitting and listening events performance comparison Subscribe to RSS

Suppose when importing component B, which fires a method defined in the parent component A

Component B:

….,
methods: {
onSomeEvent: function() {
this.$parent.doSomething();
}
},
….

Component A:

import ComponentB from ‘componentB.vue’
….,
methods: {
doSomething: function() {
console.log(‘Something done by the parent’);
}
},
….

The other way to achieve the same effect would be to emit event in Component B and then listening to it in Component A:

Component B:

….,
methods: {
onSomeEvent: function() {
this.$emit(‘eventForParent’);
}
},
….

Component A:

….
<ComponentB @eventForParent=”doSomething()” />
….

import ComponentB from ‘componentB.vue’

….,
methods: {
doSomething: function() {
console.log(‘Something done by the parent’);
}
},
….

The first approach has a draw back, it only works if B is the direct child of A while the second approach works with indirect imports as well. But does it come at a cost if we are talking about a complex UI/UX design?

Is the first approach faster than second one? Any help would be appreciated?

Solution :

This question is bound to be flagged as being open to opinion. However - I’ll do my best to answer:

In short - it really depends on the use case.
If you’re building a component that you will re-use throughout the project, or in other projects (say for example, a simple datepicker), it would be best to take the route of passing properties and emitting events. Doing so gives the flexibility of not relying on what methods are available in it’s parent component.

However, if the component is only being used in one specific place - then it might be OK to go down the route of using Vue.$parent(). However - you should consider whether having logic in the parent component is necessary, if it will only be used to control the child component. So even in this case, using events and properties would possibly be the better option.

One case where using Vue.$parent() is very useful, and suitable - is when you have a component nested through <router-view>. Passing properties and setting up events in this case wouldn’t be suitable - so, if there is a method in the parent component that you needed to access - Vue.$parent() would be a good solution here.

[Vue.js] How can I chain dynamic imports with meteor? Subscribe to RSS

My use case

I work on a large app where, depending on a user role, I load/import different modules sets. This is a meteor app, with Vue, vue-router & vue-i18n on the frontend, but no store like vuex.

Each module comes with its own routes, translation files, api & UI. Thats why I need to check that every module and its translations are loaded before I display the main UI & navigation (or else, e.g. the navigation items labels related to an unloaded module will not be translated, or the localized routes will return a 404) .

Is there a pattern, as simple as possible, to ensure that everything is loaded?

My code & logic

My use case is more complex than what I can achieve with Promise.all afaik.

I tried to make nested promises with a combination of Promises.all and then().

To sum it up, the order is:

load the base bundle
login the client
import i18n language file for the main bundle then for each module
for each module, after its language file is loaded and merged in the related i18n messages, I need to load the module itself (localized routes, UI …)

The main loading part

Accounts.onLogin(function (user) {
let userRoles = Roles.getRolesForUser(Meteor.userId())
let promises = []
let lang = getDefaultLanguage()
promises.push(loadLanguageAsync(lang))
this.modulesReady = false
for (let role of userRoles) {
switch (role) {
case “user”:
import { loadUserLanguageAsync } from “/imports/user/data/i18n”
promises.push(loadUserLanguageAsync(lang).then(import(“/imports/user/“)))
break
case “admin”:
import { loadAdminLanguageAsync } from “/imports/admin/data/i18n”
promises.push(loadAdminLanguageAsync(lang).then(import(“/imports/admin/“)))
break
default:
break
}
}

return Promise.all(promises).then(function (values) {
this.modulesReady = true // my green flag, attached to the window object
})
})

the main language loading functions

const loadedLanguages = []

// Load i18n
Vue.use(VueI18n)
export const i18n = new VueI18n()

export const getDefaultLanguage = () => {
let storedLanguage = window.localStorage.getItem(
Meteor.settings.public.brand + “_lang”
)
return Meteor.user() && Meteor.user().settings && Meteor.user().settings.language
? Meteor.user().settings.language
: // condition 2: if not, rely on a previously selected language
storedLanguage
? storedLanguage
: // or simply the browser default lang
navigator.language.substring(0, 2)
}
export const loadLanguage = (lang, langFile) => {
console.log(“LOAD LANGUAGE “ + lang)

// we store agnostically the last selected language as default, if no user is logged in.
window.localStorage.setItem(
Meteor.settings.public.brand + “_lang”,
lang
)
loadedLanguages.push(lang)
if (langFile) {
i18n.setLocaleMessage(lang, Object.assign(langFile))
}
i18n.locale = lang

return lang
}

export const loadLanguageModule = (lang, langFile) => {
console.log(“LOAD LANGUAGE MODULE” + lang)
i18n.mergeLocaleMessage(lang, Object.assign(langFile))
return lang
}

export function loadLanguageAsync(lang) {
if (i18n.locale !== lang) {
if (!loadedLanguages.includes(lang)) {
switch (lang) {

case “en”:
return import(“./lang/en.json”).then(langFile => loadLanguage(“en”, langFile))

case “fr”:
return import(“./lang/fr.json”).then(langFile => loadLanguage(“fr”, langFile))

default:
return import(“./lang/fr.json”).then(langFile => loadLanguage(“fr”, langFile))
}
} else {
console.log(“Already loaded “ + lang)

}
return Promise.resolve(!loadedLanguages.includes(lang) || loadLanguage(lang))
}
return Promise.resolve(lang)
}

The user module language loading

const userLoadedLanguages = []

export default function loadUserLanguageAsync(lang) {
if (i18n.locale !== lang || !userLoadedLanguages.includes(lang)) {
switch (lang) {
case “en”:
return import(“./lang/en.json”).then(langFile => loadLanguageModule(“en”, langFile))
case “fr”:
return import(“./lang/fr.json”).then(langFile => loadLanguageModule(“fr”, langFile))
default:
return import(“./lang/fr.json”).then(langFile => loadLanguageModule(“fr”, langFile))
}
}
return Promise.resolve(i18n.messages[lang].user).then(console.log(“USER LANG LOADED”))
}

Once every module is loaded, I switch a flag that allows my router navigation guard to proceed to the route required (see the main loading part).

The router guard and await async function

router.beforeEach((to, from, next) => {
isReady().then(
console.log(“NEXT”),
next()
)
})
async function isReady() {
while (true) {
if (this.modulesReady) { console.log(“READY”); return }
await null // prevents app from hanging
}
}

I’m quite new to the async logic and I struggle to identify what when doing wrong. The code here makes the browser crash since I guess my promises values are not the right ones and it goes in an infinite isReady() loop.

I would very much welcome suggestions or advises on the better/correct way to go. Also, feel free to request more details if something is missing.

Thanks!

Solution :

How can I chain dynamic imports with meteor?

First consider this answer on Promise chains: How do I access previous promise results in a .then() chain?

If you rather prever async/wait style you con follow up here: Dynamic imports can be called using await inside an async function. This gives you the opportunity to wrap up the code sync-style and resolve everything in a final Promise:

Consider a simple JSON file on the relative project path /imports/lang.json:

{
“test”: “value”
}

and some example exported constant on the path /imports/testObj.js:

export const testObj = {
test: ‘other value’
}

You can dynamically import these using an async function like so (example in client/main.js):

async function imports () {
const json = await import(‘../imports/lang.json’)
console.log(‘json loaded’)
const { testObj } = await import(‘../imports/test’)
console.log(‘testObj loaded’)
return { json: json.default, testObj }
}

Meteor.startup(() => {
imports().then(({ json, testObj }) => {
console.log(‘all loaded: ‘, json, testObj)
})
})

This will print in sequence

json loaded
testObj loaded
all loaded: Object { test: “value” } Object { test: “other value” }

Since the code example is quite complex and barely reproducible so I suggest you to consider this scheme to rewrite the routine in a more sync-style fashion to avoid the Promises syntax with dozens of .then branches.

[Vue.js] Vue deployment with Dokku Subscribe to RSS

My project is working and build correctly in local, in development or production, but when I try to push to my DigitalOcean Ubuntu server through Dokku it crashes

# server.js at the root
const express = require(‘express’);
const path = require(‘path’);
const serveStatic = require(‘serve-static’);

let app = express();
app.use(serveStatic(__dirname + “/dist”));

const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log(‘Listening on port ‘ + port)
});

# current vue.config.js
# note that it had no option originally but changing it didn’t solve the problem
const path = require(‘path’)

module.exports = {
publicPath: ‘/‘,
configureWebpack: {
resolve: {
alias: {
‘@’: path.resolve(__dirname, ‘src/‘)
}
}
},
css: {
loaderOptions: {
sass: {
data: `@import “src/assets/styles/helpers.scss”;`
}
}
},
pluginOptions: {}
}

And here’s the crash

- Building for production…

ERROR Failed to compile with 24 errors2:31:56 PM

These dependencies were not found:

* @/components/Errors/DefaultError in ./src/main.js
* @/components/Layouts/ChatLayout in ./src/main.js
* @/components/Layouts/DashboardLayout in ./src/main.js
* @/components/Layouts/DefaultLayout in ./src/main.js
* @/mixins/CurrentIdentityMixin in ./node_modules/cache-loader/dist/cjs.js??ref–12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref–0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/ConnectRouting.vue?vue&type=script&lang=js&, ./node_modules/cache-loader/dist/cjs.js??ref–12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref–0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Chat/Events/File.vue?vue&type=script&lang=js& and 16 others
* @/mixins/LayoutMixin in ./node_modules/cache-loader/dist/cjs.js??ref–12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref–0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js&, ./node_modules/cache-loader/dist/cjs.js??ref–12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref–0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/ConnectRouting.vue?vue&type=script&lang=js&

This is very strange, it’s as @ wasn’t recognised as shortcut in Vue, but I don’t really know how to fix it. I think setting everything with relative path manually would solve the issue (it worked at least for the layouts when I tried); it’s not really a fix though, just a bad workaround.

I also changed a few times the node / npm version, without success. Here’s the package.json

{
“name”: “askalfred-app”,
“version”: “0.1.0”,
“private”: true,
“scripts”: {
“serve”: “vue-cli-service serve”,
“build”: “vue-cli-service build”,
“lint”: “vue-cli-service lint”,
“generate”: “graphql-codegen”,
“postinstall”: “npm run build”,
“start”: “node server.js”
},
“dependencies”: {
“@sentry/browser”: “^5.4.0”,
“@sentry/integrations”: “^5.4.0”,
“actioncable”: “^5.2.2-1”,
“apollo-boost”: “^0.1.20”,
“apollo-cache-inmemory”: “^1.3.5”,
“apollo-client”: “^2.4.2”,
“apollo-link”: “^1.2.3”,
“apollo-link-http”: “^1.5.5”,
“apollo-upload-client”: “^10.0.1”,
“autosize”: “^4.0.2”,
“epic-spinners”: “^1.1.0”,
“flexboxgrid”: “^6.3.1”,
“graphql”: “^14.1”,
“graphql-ruby-client”: “^1.6.3”,
“lowdb”: “^1.0.0”,
“mkdirp”: “^0.5.1”,
“moment”: “^2.24.0”,
“shortid”: “^2.2.8”,
“showdown”: “^1.9.0”,
“tingle.js”: “^0.14.0”,
“typescript”: “^3.4.5”,
“v-mask”: “^1.3.3”,
“vue”: “^2.6.10”,
“vue-analytics”: “^5.17.0”,
“vue-apollo”: “3.0.0-beta.25”,
“vue-notification”: “^1.3.16”,
“vue-router”: “^3.0.1”,
“vuelidate”: “^0.7.4”,
“vuex”: “^3.0.1”
},
“devDependencies”: {
“@graphql-codegen/cli”: “^1.2.0”,
“@graphql-codegen/fragment-matcher”: “^1.2.0”,
“@graphql-codegen/typescript”: “^1.2.0”,
“@vue/cli-plugin-babel”: “^3.4.0”,
“@vue/cli-plugin-eslint”: “^3.5.1”,
“@vue/cli-service”: “^3.4.0”,
“eslint”: “^5.15.3”,
“eslint-config-standard”: “^12.0.0”,
“eslint-plugin-import”: “^2.16.0”,
“eslint-plugin-node”: “^8.0.1”,
“eslint-plugin-promise”: “^4.0.1”,
“eslint-plugin-standard”: “^4.0.0”,
“eslint-plugin-vue”: “^5.2.2”,
“express”: “^4.17.1”,
“graphql-tag”: “^2.9.0”,
“node-sass”: “^4.11.0”,
“sass-loader”: “^7.1.0”,
“serve-static”: “^1.14.1”,
“vue-cli-plugin-apollo”: “^0.20.0”,
“vue-template-compiler”: “^2.5.21”
},
“engines”: {
“node”: “v11.11.0”,
“npm”: “6.7.0”
},
“postcss”: {
“plugins”: {
“autoprefixer”: {}
}
},
“browserslist”: [
“> 1%”,
“last 2 versions”,
“not ie <= 8”
]
}

Any idea what I could be doing wrong?

Solution :

Somewhat working solution

For anyone which would end up in the same situation, I believe most tutorial about Dokku / VueJS are out of date, and lead to stupid mistakes, or at the very least does not tackle the deployment correctly with the newer versions. After several hours I figured:

“postinstall”: “npm run build”,

I removed this from the package.json and now it deploys without problem. I’m unsure if the success was due to removing the /dist from .gitignore in my project and building it locally, or if the something happens while it’s deployed, but it’s enough in my case.

[Vue.js] How to empty input fields from a pop-up window after submitting - Vue - laravel?html partjs part Subscribe to RSS

My page exist of a table where I can add new rows. If you want to add a new row a pop-up window appear where the new values can be added.
This new data is then saved to the database after submitting. If I again want to add a new row the input fields, they should be cleared.
The method I use, is working but isn’t very clear.

Note: My code shows only a part of the input fields, to make it more clear. My pop-up window actually contains 20 input fields.

I would like to clear them all at once instead of clearing them one by one (like when doing now).
Because when already doing this for defining the v-model, pushing the new data to the database directly on the page and via post axios request.
Is there a cleaner way to do this?
Thanks for any input you could give me.

This is my code:

html part

<div class=”col-2 md-2”>
<button class=”btn btn-success btn-sx” @click=”showModal(‘add’)”>Add New</button>
<b-modal :ref=”‘add’” hide-footer title=”Add new” size=”lg”>
<div class=”row” >
<div class=”col-4”>
<b-form-group label=”Category”>
<b-form-input type=”text” v-model=”newCategory”></b-form-input>
</b-form-group>
</div>
<div class=”col-4”>
<b-form-group label=”Name”>
<b-form-input type=”text” v-model=”newName” placeholder=”cd4”></b-form-input>
</b-form-group>
</div>
<div class=”col-4”>
<b-form-group label=”Amount”>
<b-form-input type=”number” v-model=”newAmount” ></b-form-input>
</b-form-group>
</div>
</div>
<div class=”row” >
<div class=”col-8”>
</div>
<div class=”col-4”>
<div class=”mt-2”>
<b-button @click=”hideModal(‘add’)”>Close</b-button>
<b-button @click=”storeAntibody(antibodies.item)” variant=”success”>Save New Antibody</b-button>
</div>
</div>
</div>
</b-modal>
</div>

js part

<script>
import { async } from ‘q’;
export default {
props: [‘speciedata’],
data() {
return {
species: this.speciedata,
newCategory: ‘’,
newName: ‘’,
newAmount:’’,
}
},
computed: {

},
mounted () {
},
methods: {
showModal: function() {
this.$refs[“add”].show()
},
hideModal: function(id, expId) {
this.$refs[‘add’].hide()
},
addRow: function(){
this.species.push({
category: this.newCategory,
name: this.newName,
amount: this.newAmount,
})
},
storeSpecie: async function() {
axios.post(‘/specie/store’, {
category: this.newCategory,
name: this.newName,
amount: this.newAmount,
})
.then(this.addRow())
// Clear input
.then(
this.newName = ‘’,
this.newCategory = ‘’,
this.newAmount = ‘’,
)
.then(this.hideModal(‘add’))
},
}
}

</script>

Solution :

in the data of vuejs app , you have to set one object for displaying modal data like modalData then to reset data you can create one function and set default value by checking type of value using loop through modalData object keys

var app = new Vue({
el: ‘#app’,
data: {
message:”Hi there”,
modalData:{
key1:”value1”,
key2:”value2”,
key3:”value3”,
key4:5,
key5:true,
key6:”val6”
}
},
methods: {
resetModalData: function(){
let stringDefault=””;
let numberDefault=0;
let booleanDefault=false;

Object.keys(this.modalData).forEach(key => {
if(typeof(this.modalData[key])===”number”){
this.modalData[key]=numberDefault;
}else if(typeof(this.modalData[key])===”boolean”) {
this.modalData[key]=booleanDefault;
}else{
// default type string
this.modalData[key]=stringDefault;
}

});

}
}
})
<script src=”https://cdn.jsdelivr.net/npm/vue"></script>

<div id=”app”>
{modalData}
<br/>
<button @click=”resetModalData”>Reset Modal Data</button>
</div>

update : in the case :

data:{

species: this.speciedata,
modalData:{
newCategory: ‘’,
newName: ‘’,
newAmount:’’
}
},

and after storing data :

storeSpecie: async function() {
axios.post(‘/specie/store’, {
category: this.newCategory,
name: this.newName,
amount: this.newAmount,
})
.then(()=>{
this.addRow();
this.resetModalData();
this.hideModal(‘add’)
}

},

Solution 2:

In native Javascript you get the reset() method.

Here is how it is used :

document.getElementById(“myForm”).reset();

It will clear every input in the form.