Laravel inertia render blank page on IPhone device - javascript

Issue:
I have a laravel 9 app builded with vue3 , inertia-laravel , inertiajs and laravel-vite , it works perfetct on PC but when I try to open it in mobile device It show a blank page without any console log.
NB : when I toggle device toolbar to mobile in a navigator it works correctly but in real mobile no ( I tested on different navigators)
I can't fix this issue come from inertiajs\inertia-vue3 or inertiajs/inertia-laravel
When I render a blade view it works, just when I render inertia object
Versions:
inertiajs/inertia-laravel version: 0.6.3
#inertiajs/inertia version: 0.11.0
#inertiajs/inertia-vue3 version: 0.6.0
Codes:
web.php:
Route::get('/', function() {
return Inertia::render('WelcomeView');
});
app.js
import './bootstrap';
import '../css/main.css'
import { createPinia } from 'pinia'
import { useStyleStore } from '#/Stores/style.js'
import { darkModeKey } from '#/config.js'
import { createApp, h } from 'vue'
import { createInertiaApp } from '#inertiajs/inertia-vue3'
import { InertiaProgress } from '#inertiajs/progress'
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m'
import Notifications from 'notiwind'
import * as ConfirmDialog from 'vuejs-confirm-dialog'
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel'
const pinia = createPinia()
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
setup({ el, app, props, plugin }) {
return createApp({ render: () => h(app, props) })
.use(plugin)
.use(pinia)
.use(Notifications)
.use(ConfirmDialog)
.use(ZiggyVue, Ziggy)
.mount(el);
},
});
InertiaProgress.init({
color: '#5136a8',
showSpinner:true
})
const styleStore = useStyleStore(pinia)
/* App style */
//styleStore.setStyle(localStorage[styleKey] ?? 'basic')
styleStore.setStyle()
/* Dark mode */
if ((!localStorage[darkModeKey] && window.matchMedia('(prefers-color-scheme: dark)').matches) || localStorage[darkModeKey] === '1') {
styleStore.setDarkMode(true)
}
WelcomeVue.vue (under pages folder) :
<template>
<div>
hellow world
</div>
</template>
and app.blade.php :
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{!! csrf_token() !!}" />
<title inertia>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<!-- Scripts -->
#routes
#vite('resources/js/app.js')
#inertiaHead
</head>
<body class="font-sans antialiased">
#inertia
</body>
</html>

Related

pass data from vue.js to laravel 9

Problem: internal server error while passing data from vue.js to laravel using axios
I created fresh laravel project and installed breeze with vue (php artisan breeze:install vue). Then I created One menu controller and rendered menu.vue like this :
public function index()
{
$menuItems = Menu::all();
return Inertia::render('Menu', [
'menuItems' => $menuItems
]);
}
Route::get('menu',[MenuController::class,'index']);
Now I created CartController
<?php
namespace App\Http\Controllers;
use App\Models\Cart;
use App\Models\Menu;
use Illuminate\Http\Request;
class CartController extends Controller
{
public function store(Request $request)
{
dd("CONTROLLER");
$menu_id = $request->input('id');
$menu = Menu::find($menu_id);
$cart=new Cart();
$cart->table=$request->table;
$cart->menus_id=$menu_id;
$response=$cart->save();
}
}
and here I have to store data returned from menu.vue
Menu.vue
<script setup>
import { Head } from '#inertiajs/vue3';
</script>
<template>
<Head title="Menu" />
<navbar />
<div
class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4 mx-20"
>
<div v-for="item in menuItems" :key="item.id">
<div class="p-6 bg-white rounded-lg shadow-lg">
<img
v-bind:src="'menuItemImage/' + item.image"
class="w-12 h-12"
/>
<h3 class="text-lg font-medium leading-tight">
{{ item.name }}
</h3>
<button
#click="addToCart(item)"
class="mt-4 bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600"
>
Add
</button>
</div>
</div>
</div>
</template>
<script>
import navbar from "#/Layouts/NavbarLayout.vue";
import axios from "axios";
export default {
name: "Menu",
data() {
return {};
},
components: {
navbar,
},
props: ["menuItems"],
methods: {
addToCart(item) {
console.log(item.id);
axios
.post("/cart", {
menu_id: item.id,
})
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
},
},
};
</script>
The problem is when This called
axios
.post("/cart", {
menu_id: item.id,
})
It gives me this error:
error
This is my app.js
axios
import './bootstrap';
import '../css/app.css';
import { createApp, h } from 'vue';
import { createInertiaApp } from '#inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
setup({ el, App, props, plugin }) {
return createApp({ render: () => h(App, props) })
.use(plugin)
.use(ZiggyVue, Ziggy)
.mount(el);
},
progress: {
color: '#4B5563',
},
});
This is my app.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title inertia>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="stylesheet" href="https://fonts.bunny.net/css2?family=Nunito:wght#400;600;700&display=swap">
<!-- Scripts -->
#routes
#vite(['resources/js/app.js', "resources/js/Pages/{$page['component']}.vue"])
#inertiaHead
</head>
<body class="font-sans antialiased">
#inertia
</body>
</html>
This is in storage/log file[2023-02-08 16:39:49] local.ERROR: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'menus_id' cannot be null (SQL: insert into carts (menus_id, table, updated_at, created_at) values (?, ?, 2023-02-08 16:39:49, 2023-02-08 16:39:49)) {"exception":"[object] (Illuminate\\Database\\QueryException(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'menus_id' cannot be null (SQL: insert into carts (menus_id, table, updated_at, created_at) values (?, ?, 2023-02-08 16:39:49, 2023-02-08 16:39:49)) at D:\\Trinity\\7th sem\\Project work\\smart_QR_based_restaurant\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php:760) [stacktrace]
This might be your issue,
you are passing this object as the post data
{menu_id: item.id}
then you call a non-existing input in your controller $request->input('id')
$menu_id = $request->input('id');
$menu = Menu::find($menu_id);
it should be $request->input('menu_id');
but again, check your logs to see the actual error thrown
also, you should add a validation in your controller to make sure the ID you pass exist in your table
public function store(Request $request) {
$request->validate([
'menu_id' => 'required|exists:menus,id'
]);
$menu_id = $request->input('menu_id');
$menu = Menu::find($menu_id);
$cart=new Cart();
$cart->table=$request->table;
$cart->menus_id=$menu_id;
$response=$cart->save();
}
I passed menu_id from post menu.vue but $cart->table gets null value so I got this error : Integrity constraint violation
so for now I give this value directly
public function store(Request $request)
{
$menu_id = $request->input('menu_id');
$menu = Menu::find($menu_id);
$cart = new Cart();
$cart->menus_id = $menu_id;
$cart->table = 2;
$response = $cart->save();
}
Thank you guys for helping me 😊

Start embedded react app with the external parameters

I have a react app embedded in a webpage and the app should start with parameters it gets from the page. Now I pass the parameters on index.HTML file in a div but the problem is if the parameters are updated the app won't notice the changes.
index.HTML
<html>
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Sales flow</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div class="staringId" packageId="2" itemId="5" channelId="9"></div>
</body>
</html>
index.js
import './index.scss';
import App from './App'
const div = document.querySelector('.staringId')
ReactDOM.render(
<App domElement={div} />,
div
);
App.js
const App = ({ domElement }) => {
const package = domElement.getAttribute("packageId")
const item = domElement.getAttribute("itemId")
const channel = domElement.getAttribute("channelId")
const [data, setData] = useState({
packageId: '',
itemId: '',
channelId: '',
})
useEffect(() => {
setSelData({
packageId: package,
itemId: item,
channelId: channel,
})
}, [package, item, channel])
}
javascript file to embed the app
<div class="staringId" packageId="2" itemId="5" channelId="9"</div>
<script src="./dist/runtime-main.8d32315e.js"></script>
<script src="./dist/2.4c89be1e.chunk.js"></script>
<script src="./dist/main.a41deb26.chunk.js"></script>
My question is how I can pass some external parameters to the app and update(restart) the app after each update to the parameters.
The idea is to have only one top-level component in your HTML, and whatever parameters(props) you are trying to pass sit on the other components within the top-level . Following is the rough structure how it would look like.
index.html
<html>
<body>
<div id="app"></div>
</body>
</html>
index.js
import './index.scss';
import App from './App'
ReactDOM.render(
<App packageId="2" itemId="5" channelId="9" />, // you can choose to dynamically pass the value depends on what you get from page
document.getElementById("app")
);
App.js
const App = ( props ) => {
// props.packageId and etc are available here
// you can then choose to render it with these props value
return (
<MyOtherComponent otherProps="ifany" />
);
}
export default App;

How to pass JSON variable to Vue App + Components

I have a simple index.html file. It includes the Vue JS application and has the following code.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test</title>
<script>
const foo = {
bar: 100
};
</script>
<script src="main.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
Here's how the Vue JS app looks like.
main.js
import Vue from "vue"
import App from "./App.vue"
Vue.config.productionTip = false
new Vue({
render: h => h(App)
}).$mount("#app")
App.vue
<template>
<div>
{{ config.bar }}
</div>
</template>
<script>
export default {
props: {
config: {
type: Object,
default: () => {},
},
}
}
</script>
I simply want to pass the const foo variable into the App.vue file. I already tried to pass it as a prop to the <div id="app" :config="foo"></div>, however it did throw an undefined error in App.vue.
How can I pass a JS variable from HTML into a Vue Application and to the component?

Use a vanilla JavaScript package in React app

I am aiming to use a Vanilla JavaScript package in a more sophisticated React app to build additional logic around the JavaScript package.
The JavaScript library is LabelStudio and docs can be found here: https://github.com/heartexlabs/label-studio-frontend
However, when I try to import the LabelStudio I get an error saying Module not found: Can't resolve 'label-studio' , as described here https://github.com/heartexlabs/label-studio-frontend/issues/55
Since my understanding of frontend code is limited, I am not sure whether this is something the developers did not expected users to do and just wanted them to use the entire library and customized instead of using the library as a component. My idea was to use the library as in the vanilla javascript example here:
<!-- Include Label Studio stylesheet -->
<link href="https://unpkg.com/label-studio#0.7.1/build/static/css/main.0a1ce8ac.css" rel="stylesheet">
<!-- Create the Label Studio container -->
<div id="label-studio"></div>
<!-- Include the Label Studio library -->
<script src="https://unpkg.com/label-studio#0.7.1/build/static/js/main.3ee35cc9.js"></script>
<!-- Initialize Label Studio -->
<script>
var labelStudio = new LabelStudio('label-studio', {
config: `
<View>
<Image name="img" value="$image"></Image>
<RectangleLabels name="tag" toName="img">
<Label value="Hello"></Label>
<Label value="World"></Label>
</RectangleLabels>
</View>
`,
interfaces: [
"panel",
"update",
"controls",
"side-column",
"completions:menu",
"completions:add-new",
"completions:delete",
"predictions:menu",
],
user: {
pk: 1,
firstName: "James",
lastName: "Dean"
},
task: {
completions: [],
predictions: [],
id: 1,
data: {
image: "https://htx-misc.s3.amazonaws.com/opensource/label-studio/examples/images/nick-owuor-astro-nic-visuals-wDifg5xc9Z4-unsplash.jpg"
}
},
onLabelStudioLoad: function(LS) {
var c = LS.completionStore.addCompletion({
userGenerate: true
});
LS.completionStore.selectCompletion(c.id);
}
});
</script>
How can I make use of the above code in a React Component to facilitate dynamic data loading and use of state to customize the functions?
I don't have a solution making the npm module label-studio to work. I tried importing the dist file instead, but it errors
Expected an assignment or function call and instead saw an expression
So here's a workaround until the maintainers address this.
Copy the JS file from build/static/js, then place it in a script in the public folder on index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="%Your_Path_To_Label-Studio%/main.js"></script>
</body>
</html>
The script file defines a global function variable, so you can access it in React by using the window object. The useEffect hook is to make sure the initialization is only run once.
import React, { useEffect, useRef } from "react";
function App() {
const LabelStudio = window.LabelStudio; // label-studio script stores the api globally, similar to how jQuery does
const myLabelStudioRef = useRef(null); // store it and then pass it other components
useEffect(() => {
myLabelStudioRef.current = new LabelStudio("label-studio", {
config: `
<View>
<Image name="img" value="$image"></Image>
<RectangleLabels name="tag" toName="img">
<Label value="Hello"></Label>
<Label value="World"></Label>
</RectangleLabels>
</View>
`,
interfaces: [
"panel",
"update",
"controls",
"side-column",
"completions:menu",
"completions:add-new",
"completions:delete",
"predictions:menu",
],
user: {
pk: 1,
firstName: "James",
lastName: "Dean",
},
task: {
completions: [],
predictions: [],
id: 1,
data: {
image:
"https://htx-misc.s3.amazonaws.com/opensource/label-studio/examples/images/nick-owuor-astro-nic-visuals-wDifg5xc9Z4-unsplash.jpg",
},
},
onLabelStudioLoad: function (LS) {
var c = LS.completionStore.addCompletion({
userGenerate: true,
});
LS.completionStore.selectCompletion(c.id);
},
});
}, []);
return (
<div className="App">
{/* Use Label Studio container */}
<div id="label-studio"></div>
</div>
);
}
export default App;
As far as storing the new instance of LabelStudio, there's many ways to go about it. You can store it as variable on the root component using either useState or useRef hooks and then pass it to child components. If you want to avoid manually passing variable down the component tree, then you need a state manager such as React Context or Redux.
This is the basic setup using LabelStudio as a module in a React component.
yarn add #heartexlabs/label-studio
import LabelStudio from '#heartexlabs/label-studio'
import { useEffect } from 'react'
import '#heartexlabs/label-studio/build/static/css/main.css'
const ReactLabelStudio = () => {
useEffect(() => {
new LabelStudio('label-studio', {
config: {...},
interfaces: [...],
user: {...},
task: {...},
onLabelStudioLoad: function(LS) {
const c = LS.annotationStore.addAnnotation({
userGenerate: true,
});
LS.annotationStore.selectAnnotation(c.id);
}
})
}, [])
return <div id="label-studio" />
}
export default ReactLabelStudio

REACT-NATIVE - abcjs - ReferenceError: Can't find variable: Element

import abcjs from 'abcjs';
export default class MusicScore extends Component {
constructor(props) {
super(props);
this.state={
data: this.props.navigation.getParam('abctune'),
}
}
render(){
data = this.state.data;
renderScore = () => {
abcjs.renderAbc('notation', data);
}
return(
<WebView
source={
{html: `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="notation"></div>
</body>
</html>
`}
}
domStorageEnabled
javaScriptEnabled
injectJavaScript={renderScore}
/>
);
}
}
The code above produces the following
OUTPUT
dev enviornment:
OS: Windows 10
node: v12.10.0
Android Studio: 3.5.2
installed via package manager:
npm install --save abcjs
Unfortunately, you need a DOM set up. I haven't used react-native, so I'm not sure if this will work:
What works for me when using a SSR package (like Nuxt) is to change the import to later in the process. So:
mounted() {
const abcjs = require('abcjs');
}
Is there something analogous in react-native?

Categories