My original app.js looked like this. I noticed I can't add Vue directives because the createApp has no variable.
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => require(`./Pages/${name}.vue`),
setup({ el, app, props, plugin }) {
return createApp({ render: () => h(app, props) })
.use(plugin)
.mixin({ methods: { route } })
.mount(el);
},
});
After some research this lead me to this where the directive still doesn't work. Any tips?
const clickOutside = {
beforeMount: (el, binding) => {
el.clickOutsideEvent = event => {
// here I check that click was outside the el and his children
if (!(el == event.target || el.contains(event.target))) {
// and if it did, call method provided in attribute value
binding.value();
}
};
document.addEventListener("click", el.clickOutsideEvent);
},
unmounted: el => {
document.removeEventListener("click", el.clickOutsideEvent);
},
};
const el = document.getElementById('app');
const app = createApp({
render: () =>
h(InertiaApp, {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: (name) => require(`./Pages/${name}`).default,
}),
});
app.directive('click-outside', clickOutside);
app.mixin({ methods: { route } })
.mixin({ directives: { clickOutside } })
.use(InertiaPlugin);
app.mount(el);
Related
I started my first project with Laravel + Vite (I already used Inertia with Laravel + Webpack) and the problem I have is the default layout.
When using Webpack I could define the layout with the following code:
createInertiaApp({
resolve: name => {
const page = require(`../svelte/Pages/${name}.svelte`);
if (guestPages.indexOf(name) !== -1) {
page.layout = LayoutGuest
} else {
page.layout = Layout
}
return page
},
setup({ el, App, props }) {
new App({ target: el, props })
},
})
But now, with the new Vite way, I can't get it to work.
Here's the code I have:
async function resolve(name)
{
const page = resolvePageComponent(`../svelte/Pages/${name}.svelte`, import.meta.glob('../svelte/Pages/**/*.svelte'));
let component;
await page
.then(module => {
module.default.layout = Layout;
component = module;
});
return component;
I don't know if the problem is the dynamic import.
With the help of an Inertia server member on Discord (Robert Boes) and writing a few lines of code, I found the solution:
// import './bootstrap';
import { createInertiaApp } from '#inertiajs/inertia-svelte'
import { resolvePageComponent } from "laravel-vite-plugin/inertia-helpers";
import "../less/app.less";
import Layout from "../svelte/Base/Layout.svelte";
async function resolve(name)
{
let component;
const pagesWithoutLayout = [
'Session/Index',
];
const page = resolvePageComponent(`../svelte/Pages/${name}.svelte`, import.meta.glob('../svelte/Pages/**/*.svelte'));
await page
.then(module => {
component = pagesWithoutLayout.includes(name) ?
module :
Object.assign({ layout: Layout }, module);
});
return component;
}
createInertiaApp({
resolve,
setup({ el, App, props }) {
new App({ target: el, props })
},
});
I made it work without Svelte with the following code snipped.
Hope it helps and maybe you can adapt it to your needs.
Im using it in a TypeScript environment, which is why I added "as any;".
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: async (name) => {
const page = resolvePageComponent(
`./Pages/${name}.vue`,
import.meta.glob("./Pages/**/*.vue")
) as any;
await page.then((module) => {
//if name starts with auth, then use login layout
if (name.startsWith("Auth/")) {
module.default.layout = module.default.layout || LoginLayout;
} else if (name.startsWith("Public/")) {
module.default.layout = module.default.layout;
} else {
module.default.layout = module.default.layout || AppLayout;
}
});
return page;
},
setup({ el, app, props, plugin }) {
createApp({ render: () => h(app, props) })
.use(plugin)
.use(createPinia())
.mount(el);
},
});
I tried importing vue-moment and initializing it by using .use(VueMoment) as shown below. But after i do that the whole app shows error. Anyone facing the same problem?
require('./bootstrap');
// Import modules...
import { createApp, h } from 'vue';
import { App as InertiaApp, plugin as InertiaPlugin } from '#inertiajs/inertia-vue3';
import { InertiaProgress } from '#inertiajs/progress';
import VueMoment from 'vue-moment' ////////imported vue-moment
const el = document.getElementById('app');
createApp({
render: () =>
h(InertiaApp, {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: (name) => require(`./Pages/${name}`).default,
}),
})
.mixin({
methods: {
route,
validationError(field){
if(this.$page.props.errors && this.$page.props.errors[field]){
return this.$page.props.errors[field];
}
else{
return null;
}
}
} })
.use(InertiaPlugin)
.use(VueMoment) /////use vue-moment
.mount(el);
InertiaProgress.init({ color: '#4B5563' });
This is the error i am getting
first install moment by
npm install moment
<template>
{{today}}
</template>
<script>
import moment from 'moment'
export default {
name:'Home',
data(){
return{
today:moment().startOf('day').toDate(), moment().endOf('day').toDate()
}
}
</script>
there is a working example of how to import 'vue-moment' from my Laravel + inertia project
const vm = new Vue({
metaInfo: {
titleTemplate: title => (title ? `${title} - Ping CRM` : 'Ping CRM'),
},
store,
render: h =>
h(App, {
props: {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: name => import(`#/Pages/${name}`).then(module => module.default),
},
}),
}).$mount(el)
Vue.use(require('vue-moment'))
Might help someone who is using InertiaJs with Vue and want to declare globally.
In app.js
createInertiaApp({
id: 'app',
setup({ el, App, props}) {
let app = createApp({
render: () => {
return h(App, props);
},
});
//you can declare any other variable you want like this
app.config.globalProperties.$moment = moment;
app.use(
store,
.....
).mount(el);
},
});
Now in the vue file you can call moment by
this.$moment(this.time,'H:m').format('hh:mm a');
I'm trying to call apiAction in constructor method through the dispatch redux method in ReactJS Component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import './styles.scss'
import { fetchData, testSet } from '../../../../../event/src/cg-store/actions';
class AppDetails extends Component {
constructor(props) {
super(props);
this.state ={
testowaZmienna: ''
}
this.props.fetchData('5576900');
}
componentDidMount() {
document.addEventListener('click', () => {
this.props.addCount()
});
this.props.testSet()
this.props.fetchData('5576900');
console.log('dhsadhnaskjndaslndsadl-----------------------------------------')
}
render() {
const { error, test, count, testSetData, data } = this.props;
return (
<div>
TEST--------------------------
Count: {count}
Error: {error}
Test: {test}
TestSet: {testSetData}
Fetch: {data[0]}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
count: state.count,
test: state.cg.test,
data: state.cg.data,
error: state.cg.error,
testSetData: state.cg.testSet,
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: (offerId) => dispatch(fetchData(offerId)),
addCount: () => dispatch({
type: 'ADD_COUNT'
}),
testSet: () => dispatch(testSet()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(AppDetails);
As you can see there is addCount, testSet and fetchData methods. addCount and testSet works but problem is with fetchData:
This is apiAction method:
const fetchProductsPending = () => {
return {
type: actionTypes.FETCH_DATA_PENDING
};
};
const fetchProductsSuccess = fetchedData => {
return {
type: actionTypes.FETCH_DATA_SUCCESS,
data: fetchedData
};
};
const fetchProductsError = errorMessage => {
return {
type: actionTypes.FETCH_DATA_ERROR,
error: errorMessage
};
};
export const testSet = () => {
return {
type: actionTypes.TEST_SET
};
};
export const fetchData = (offerId) => (dispatch) => {
console.log('Im inside fetch before set pending'); // It does not want to go here
dispatch(fetchProductsPending());
axios
.get(config.api.host + offerId, {
headers: {
"Content-Type": "application/json",
}
})
.then(response => {
return response.data;
})
.then(response => {
dispatch(fetchProductsSuccess(response.data));
console.log("Fetch data success: ----------------------");
console.log(response.data);
})
.catch(error => {
dispatch(fetchProductsError(error.statusText));
console.log("Fetch data success: ----------------------");
console.log(error);
});
};
So as you can see testSet works fine but fetchData does not want to work.
What I'm doing wrong?
I'm not sure if I'm doing it correctly, I just followed their documentation.
I'm using mocha + sinonjs
actions.js
import axios from 'axios';
export const attachmentActions = {
getAttachment(id) {
axios.get('/api/attachment/${id}')
.then(response => {
console.log(respons);
})
.catch(error => {
console.log(error);
})
}
}
export const actions = {
...attachmentActions,
}
actions.test.js
describe('actions-test', () => {
let server;
beforeEach(() => {
server = sinon.createFakeServer();
});
afterEach(() => {
server.restore();
})
it('call getAttachment', () => {
server.requests[0].respond(200,
{'Content-type':'application/json'},
JSON.stringify({mimeType: 'image/png', path: '/user/image/'}));
actions.getAttachment(1)
//assertion
})
})
With the code above I got TypeError: Cannot read property 'respond' of undefined
I also tried below
it('call getAttachment', () => {
server.respondWith('GET','/api/attachment/1',[200,
{'Content-type':'application/json'},
JSON.stringify({mimeType: 'image/png', path: '/user/image/'}))];
actions.getAttachment(1);
server.respond();
//assertion
})
but when I run the test axios returns 404
Would really appreciate if someone can pinpoint if I miss something?
sinon version: 7.3.2
Using an EventBus on my Laravel-Vuejs project. I'm emitting an items-updated event from ItemCreate component after the successful Item creation. On the same page I'm using ItemList component which shows a list of created Items
Here is the codes:
app.js file
require('./bootstrap');
window.Vue = require('vue');
window.EventBus = new Vue();
Vue.component('item-list',
require('./components/entities/item/ItemList'));
Vue.component('item-create',
require('./components/entities/item/ItemCreate'));
const app = new Vue({
el: '#app'
});
ItemCreate.vue Component
export default {
data: function () {
return {
itemName: ''
}
},
methods: {sendItemData: function () {
axios.post('/dashboard/item', {
name: this.itemName
})
.then(response => {
if (response.status === 201) {
toastr.success('Item created successfully!', {timeout: 2000});
EventBus.$emit('items-updated');
}
})
.catch(error => {
toastr.error(error, 'Ooops! Something went wrong!');
})
}
}
}
ItemList.vue Component
export default {
data: function () {
return {
items: [],
}
},
methods: {
getItems: function () {
axios.get('/dashboard/items')
.then(response => {
this.items = response.data;
})
.catch(error => {
toastr.error(error, 'Ooops! Something went wrong!');
})
}
},
mounted() {
this.getItems();
EventBus.$on('items-updated', function () {
this.getItems();
});
}
}
It was a general JS mistake. Working code:
on ItemList.vue Component
export default {
data: function () {
return {
items: [],
}
},
methods: {
getItems: function () {
axios.get('/dashboard/items')
.then(response => {
this.items = response.data;
})
.catch(error => {
toastr.error(error, 'Ooops! Something went wrong!');
})
}
},
mounted() {
this.getItems();
let vm = this;
EventBus.$on('items-updated', function () {
vm.getItems();
});
}
}