I'm trying to implement a routing functionality for an <ul> element. Basically, the 3 <li> elements should be links to other components (test1, test2, test3). There's an extra routing for home page.
This is what I tried so far:
const m = require("mithril");
const test1 = require('./test1.js');
const test2 = require('./test2.js');
const test3 = require('./test3.js');
var root = document.body;
var home = {
view: function() {
return m(
m(NavbarComponent,{
oncreate: (vnode) => setupRouting(vnode.dom)
},
navbar)
);
}
};
var NavbarComponent = {
view: function(vnode) {
return m("ul", vnode.attrs, [vnode.children]);
}
}
const navbar = [
m("li", getRoute("test1")),
m("li", getRoute("test2")),
m("li", getRoute("test3"))
];
function getRoute(route){
return m(m.route.Link, { href: "/" + route}, route);
}
function setupRouting(element){
m.route.prefix = '';
m.route(element, "/", {
"/": home,
"/test1": test1,
"/test2": test2,
"/test3": test3,
});
}
m.mount(root, home);
The error shown in the console when loading the home page:
Uncaught DOMException: Failed to execute 'replaceState' on 'History': A history state object with URL 'file:///' cannot be created in a document with origin 'null' and URL 'file:///Users/.../webapp/index.html#!/test1'.
at setPath (webpack://resources/./node_modules/mithril/api/router.js?:154:52)
at loop (webpack://resources/./node_modules/mithril/api/router.js?:130:4)
at resolveRoute (webpack://resources/./node_modules/mithril/api/router.js?:89:3)
Edit:
The problem seems to be caused by m.route.prefix = '';
Any help is appreciated, thank you!
Related
I've been experimenting with the new composition-api in VueJS and am not sure how to solve a problem. I'm looking for some advice on how to properly implement a solution. This wasn't a problem when everything was vuex-based since you can dispatch an action to another module without a problem. However, I'm struggling to find a solution for the composition implementation.
Problem:
Component calls a CompositionA's function.
CompositionA triggers a login function.
On CompositionA's login success/failure response I would like to call a CompositionB function. (CompositionB contains data and logic for showing a snackbar that's used across the site)
The problem is that it is necessary to inject the snackbar dependency in every component rather than have it be instantiated/mounted from CompositionA. Current solution is to this effect:
Component.vue:
// template calls login(credentials) method
import { useCompositionA } from '#/compositions/compositionA'
import { useCompositionB } from '#/compositions/compositionB'
export default {
name: 'Component',
setup(props, context) {
const { login } = useCompositionA(props, context, useCompositionB(props, context))
return {
login
}
},
}
compositionA.js:
export const useAuth = (props, context, snack) => {
const login = async (credentials) => {
try {
return await loginWithEmailPassword(credentials)
snack.show({text: 'Welcome back!'})
} catch (err) {
snack.show({text: 'Failed to login'})
}
}
return { login }
}
compositionB.js:
export const useSnack = (props, context) => {
const snack = reactive({
color: 'success',
text: null,
timeout: 6000,
visible: true,
})
const snackRefs = toRefs(snack)
const show = ({ text, timeout, color }) => {
snackRefs.text.value = text
snackRefs.timeout.value = timeout || 6000
snackRefs.color.value = color || 'success'
snackRefs.visible.value = true
}
return {
...snackRefs,
show
}
}
Would be nice if something like below existed, but I'm finding that the properties aren't reactive in CompositionB if it's used from CompositionA (method gets called but snackbar doesn't show up). My understanding is that Vue isn't injecting CompositionB into the Component, so I'm just running another instance of CompositionB inside CompositionA. What am I doing something wrong? What's the proper solution here?
compositionA.js (not working):
import { useCompositionB } from '#/compositions/compositionB'
export const useAuth = (props, context) => {
const login = async (credentials) => {
const { show } = useCompositionB()
try {
return await loginWithEmailPassword(credentials)
show({text: 'Welcome back!'})
} catch (err) {
show({text: 'Failed to login'})
}
}
return { login }
}
Thanks in advance,
As expected it was due to the Component referencing its own local copy of CompositionB*. Solution is actually to bring the state of your compositions into the global scope according to:
https://vueschool.io/articles/vuejs-tutorials/state-management-with-composition-api/
Something like this:
compositionB.js:
const snack = reactive({
color: 'success',
text: null,
timeout: 6000,
visible: true,
})
export const useSnack = (props, context) => {
const snackRefs = toRefs(snack)
const show = ({ text, timeout, color }) => {
snackRefs.text.value = text
snackRefs.timeout.value = timeout || 6000
snackRefs.color.value = color || 'success'
snackRefs.visible.value = true
}
return {
...snackRefs,
show
}
}
Works like a charm.
Only caveat I found initially was a composition-api error:
Uncaught Error: [vue-composition-api] must call Vue.use(plugin) before using any function.
This was easily solved by mounting the composition-api first thing in main.js as per solution here:
Uncaught Error: [vue-composition-api] must call Vue.use(plugin) before using any function
I think this won't be a problem with vue3 comes out. Hope this helps someone.
I have this _id.vue page on my Nuxt.js project:
<template>
<div class="wrapper">
<HeaderApp>
<DivHeaderMenu>
</DivHeaderMenu>
</HeaderApp>
<CenterContentDinamicFirmenistorieApp>
</CenterContentDinamicFirmenistorieApp>
<FooterApp>
</FooterApp>
</div>
</template>
<script>
//company_history
import axios from 'axios';
import HeaderApp from '~/components/HeaderApp';
import FooterApp from '~/components/FooterApp';
import CenterContentDinamicFirmenistorieApp from '~/components/CenterContentDinamicFirmenistorieApp'
import DivHeaderMenu from '~/components/DivHeaderMenu';
import Pixelperfect from '~/components/Pixelperfect';
export default{
async fetch ({ store, params, redirect, app}) {
return axios.get('http://seo-gmbh.eu/json/api_sunds.php?action=get_pages&url=company_history')
.then((res) => {
store.commit('company_history/init_data_for_firmenistorie', res.data);
})
},
async validate({store, params, redirect}) {
const urlData = store.state.company_history.dbFirmenstorie.dbFirmenistorieSortArrayData;
let resultArray = false;
for (let i = 0; i < urlData.length; i++) {
if(params.id === urlData[i].toString()){
return resultArray = urlData[i];
}
}
if(resultArray == false){
return redirect('/Firmenistorie');
}
},
head () {
return {
title: this.$store.state.company_history.dbFirmenstorie.dbFirmenistorieData.data.meta.title,
meta: [
{description: this.$store.state.company_history.dbFirmenstorie.dbFirmenistorieData.data.meta.description}
]
}
},
components:{
HeaderApp,
FooterApp,
CenterContentDinamicFirmenistorieApp,
DivHeaderMenu,
Pixelperfect
},
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
My task is to get a redirect when I get the 404th error on the dynamic page (_id). The whole implementation works fine if I go through nuxt-link (s) to similar pages - the 404th error works fine if I enter an incorrect URL in the address bar. But the problem appears if I'm already on a working page - I reload it. Instead of loading the same page again, I get the 404th error and redirect as a result. This happens because in this particular case I do not receive data from the store
My question is: How can I solve this (asynchronous, as I understand it) problem? (I tried everything that is possible - nothing helps).
My Vuex repository looks rather piled up - but just in case, I'll throw its code for a better understanding of the problem:
export const state = () => ({
dbFirmenstorie: {
dbFirmenistorieData: null,
dbFirmenistorieMaxYearData: null,
dbFirmenistorieMaxDetailsData: null,
dbFirmenistorieSortArrayData: [],
},
});
export const mutations = {
init_data_for_firmenistorie (state, uploadDbFirmenistorieData) {
state.dbFirmenstorie.dbFirmenistorieData = uploadDbFirmenistorieData;
state.dbFirmenstorie.dbFirmenistorieData.data.content_json = JSON.parse(state.dbFirmenstorie.dbFirmenistorieData.data.content_json);
state.dbFirmenstorie.dbFirmenistorieData.data.meta = JSON.parse(state.dbFirmenstorie.dbFirmenistorieData.data.meta);
for (let i = 0; i < state.dbFirmenstorie.dbFirmenistorieData.data.company_history_data.length; i++) {
if(state.dbFirmenstorie.dbFirmenistorieSortArrayData.indexOf( Number( state.dbFirmenstorie.dbFirmenistorieData.data.company_history_data[i].company_history_from_year )) == -1 ){
state.dbFirmenstorie.dbFirmenistorieSortArrayData.push(Number(state.dbFirmenstorie.dbFirmenistorieData.data.company_history_data[i].company_history_from_year));
}
if(state.dbFirmenstorie.dbFirmenistorieMaxYearData < Number(state.dbFirmenstorie.dbFirmenistorieData.data.company_history_data[i].company_history_from_year)){
state.dbFirmenstorie.dbFirmenistorieMaxYearData = Number(state.dbFirmenstorie.dbFirmenistorieData.data.company_history_data[i].company_history_from_year);
state.dbFirmenstorie.dbFirmenistorieMaxYearData = Number(state.dbFirmenstorie.dbFirmenistorieData.data.company_history_data[i].company_history_from_year);
state.dbFirmenstorie.dbFirmenistorieMaxDetailsData = state.dbFirmenstorie.dbFirmenistorieData.data.company_history_data[i];
}
}
function sortNumber(a, b) {
return b - a;
}
state.dbFirmenstorie.dbFirmenistorieSortArrayData.sort(sortNumber);
}
};
I am pretty sure that if you start using catch() with axios as everyone should always do, you will be able to handle all non 200 responses just fine. Which means 404, 40x, 50x, etc...
axios
.get("https://example.com")
.then(res => console.log(res))
.catch(e => console.log(e))
I'm developing an Electron application and I aim to 'split up' index.js (main process) file. Currently I have put my menu bar-related and Touch Bar-related code into two separate files, menu.js and touchBar.js. Both of these files rely on a function named redir, which is in index.js. Whenever I attempt to activate the click event in my Menu Bar - which relies on redir - I get an error:
TypeError: redir is not a function. This also applies to my Touch Bar code.
Here are my (truncated) files:
index.js
const { app, BrowserWindow } = require('electron'); // eslint-disable-line
const initTB = require('./touchBar.js');
const initMenu = require('./menu.js');
...
let mainWindow; // eslint-disable-line
// Routing + IPC
const redir = (route) => {
if (mainWindow.webContents) {
mainWindow.webContents.send('redir', route);
}
};
module.exports.redir = redir;
function createWindow() {
mainWindow = new BrowserWindow({
height: 600,
width: 800,
title: 'Braindead',
titleBarStyle: 'hiddenInset',
show: false,
resizable: false,
maximizable: false,
});
mainWindow.loadURL(winURL);
initMenu();
mainWindow.setTouchBar(initTB);
...
}
app.on('ready', createWindow);
...
menu.js
const redir = require('./index');
const { app, Menu, shell } = require('electron'); // eslint-disable-line
// Generate template
function getMenuTemplate() {
const template = [
...
{
label: 'Help',
role: 'help',
submenu: [
{
label: 'Learn more about x',
click: () => {
shell.openExternal('x'); // these DO work.
},
},
...
],
},
];
if (process.platform === 'darwin') {
template.unshift({
label: 'Braindead',
submenu: [
...
{
label: 'Preferences...',
accelerator: 'Cmd+,',
click: () => {
redir('/preferences'); // this does NOT work
},
}
...
],
});
...
};
return template;
}
// Set the menu
module.exports = function initMenu() {
const menu = Menu.buildFromTemplate(getMenuTemplate());
Menu.setApplicationMenu(menu);
};
My file structure is simple - all three files are in the same directory.
Any code criticisms are also welcome; I've spent hours banging my head trying to figure all this out.
redir it is not a function, because you're exporting an object, containing a redir property, which is a function.
So you should either use:
const { redir } = require('./index.js');
Or export it this way
module.exports = redir
When you do: module.exports.redir = redir;
You're exporting: { redir: [Function] }
You are exporting
module.exports.redir = redir;
That means that your import
const redir = require('./index');
is the exported object. redir happens to be one of its keys. To use the function, use
const redir = require('./index').redir;
or destructure directly into redir
const { redir } = require('./index');
I need to grab the value of a key form URL. Let's say the URL is http://localhost:8080/foo=bar. How do I grab the value 'bar' onEnter function with in react-router so that it can be used to trigger other functions.
Thank you in advance.
URL: http://localhost:8080/foo=bar
// routes.js
var React = require('react');
var ReactRouter = require('react-router');
var Main = require('./templates/main.jsx');
var Sub = require('./templates/sub.jsx');
module.exports = {
path: '/',
component: Main,
indexRoute: { component: Main },
childRoutes: [
{
path: '/foo=:bar',
component: Sub,
onEnter: function(){
// *****************************
// grab the value 'bar' from param
}
}
]
}
The onEnter function takes two arguments. nextState and transition. The value you're looking for is inside of nextState.params:
onEnter: function(nextState, transition) {
let bar = nextState.params.bar;
}
I'm trying to write a simple test using page objects pattern - based on the 'docs/page-objects'.
I created a file describing the page object and other using this page object to test a page.
//page object
var LoginPage = function() {
this.userInput = browser.driver.findElement(by.id('username'));
this.pwdInput = browser.driver.findElement(by.id('password'));
this.btnEnter = browser.driver.findElement(by.id('btnLogin'));
this.get = function(){
browser.get('http://example.com');
};
this.setUser = function (user){
this.userInput.sendKeys(user);
};
this.setPasswd = function (password) {
this.pwdInput.sendKeys(password);
};
this.clickBtnEnter = function (){
btnEnter.click();
};};
The spec file:
var loginPage = require('./LoginPage.js');
describe('myApp', function() {
it('should save contract config', function (){
loginPage.get();
loginPage.setUser('userid');
loginPage.setPasswd('passwd');
loginPage.clickBtnEnter();
});
});
The following error is shown when I run this test: TypeError: Object # has no method 'get' - at this line: loginPage.get();.
When I was searching for this problem I found various approaches about using page objects in Protractor, such as Astrolable.
Now I am not sure about the correct usage of page objects.
Do you have any ideas about how I can fix this test?
Thank you guys.
Try this:
Ensure you have the following in your LoginPage.js file
module.exports = LoginPage;
Add the missing new keyword
var LoginPage = require('./LoginPage.js');
var loginPage = new LoginPage();
After trying the above syntax (no success) I rewrote the page object using the Astrolable. Now it works! My test looks like this:
//pageobject
'use strict';
var env = require('./environment.js')
var LoginPage = function () {
browser.driver.get('http://example.com');
};
LoginPage.prototype = Object.create({}, {
userInput: { get: function() { return browser.driver.findElement(by.id('username'));}},
pwdInput: { get: function() { return browser.driver.findElement(by.id('password'));}},
btnEnter: { get: function() { return browser.driver.findElement(by.id('btnLogin'));}},
setUser: { value: function (loginName) {
this.userInput.sendKeys(loginName);
}},
setPasswd: { value: function (loginPass) {
this.pwdInput.sendKeys(loginPass);
}},
clickBtnEnter: { get: function() { return this.btnEnter.click();}}
});
module.exports = LoginPage;
Spec file:
'use strict';
var loginPage = require('./LoginPage.js');
describe('myApp', function() {
var poLogin = new loginPage();
it('should save contract config', function (){
poLogin.setUser('userid');
poLogin.setPasswd('passwd');
poLogin.clickBtnEnter;
});
});
Now it is working fine.
Thanks for answering.