how to add this external vue component in my laravel5.3 project? - javascript

I try to add http://gritcode.github.io/gritcode-components/#/wizard in my laravel 5.3 project but when i used its nothing showing in my view here is i'm getting console "Uncaught ReferenceError: gritcode is not defined"
my app.js is.
require('./bootstrap');
Vue.component('example', require('./components/Example.vue'));
new Vue({ components: { 'vs-toast': gritcode-components.toast }})
const app = new Vue({
el: '#app',
});
and my welcome.blade.php
<div id="app">
<vs-toast>
<vs-wizard :current-index.sync="currentStep">
<vs-wizard-step
title="Personal Information"
description="Enter your details"
:progress="progress.step1"
icon="person">
</vs-wizard-step>
<vs-wizard-step
title="Payment"
description="Pay with credit card or Paypal"
:progress="progress.step2"
icon="credit-card">
</vs-wizard-step>
<vs-wizard-step
title="Confirmation"
description="Your order details"
:progress="progress.step3"
:disable-previous="true"
icon="check">
</vs-wizard-step>
</vs-wizard>
</vs-toast>
</div>
my package.json
{
"private": true,
"scripts": {
"prod": "gulp --production",
"dev": "gulp watch"
},
"devDependencies": {
"babel": "^6.5.2",
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-preset-es2015": "^6.18.0",
"bootstrap-sass": "^3.3.7",
"gritcode-components": "^0.4.7",
"gulp": "^3.9.1",
"jquery": "^3.1.0",
"laravel-elixir": "^6.0.0-9",
"laravel-elixir-vue-2": "^0.2.0",
"laravel-elixir-webpack-official": "^1.0.2",
"lodash": "^4.16.2",
"vue": "^2.0.1",
"vue-resource": "^1.0.3",
"vuestrap-base-components": "^0.8.10",
"webpack": "^1.14.0"
},
"dependencies": {
"vue-material-datepicker": "^2.0.1"
}
}
my gulpfile.js
const elixir = require('laravel-elixir');
require('laravel-elixir-vue-2');
elixir(mix => {
mix.sass('app.scss')
.webpack('app.js');
});

As the example says on the intro page you have to import them from a subdirectory of the plugin.
The example given on their website is for their toast component which has a default export, however, because wizard is made up of two components it uses named exports instead so the syntax for importing them is slightly different.
Importing default export
import foo from "someComponent"
Importing named exports
import {bar, baz} from "SomeOtherComponent"
So, for your situation you should be able to do:
require('./bootstrap');
import {wizard, wizardStep} from "gritcode-components/src/components/wizard";
const app = new Vue({
el: '#app',
components: {
'vs-wizard': wizard,
'vs-wizard-step': wizardStep
}
});
Hope this helps!

I had a similar issue and this worked for me.
import { wizard as vsWizard } from 'gritcode-components/dist/gritcode-components';
import { wizardStep as vsWizardStep } from 'gritcode-components/dist/gritcode-components';
import { toast as vsToast } from 'gritcode-components/dist/gritcode-components';
note that we are loading this from
"gritcode-components/dist/gritcode-components"
not from
"gritcode-components/src/components/wizard" as suggested in one of the answers.
then in your Vue instance you can do something like this to load the components:
require('./bootstrap');
const app = new Vue({
el: '#app',
components: {
vsWizard,
vsWizardStep,
vsToast
},
data: {
currentStep: 0
},
computed: {
progress: function() {
return {
step1: this.getStepPercentage(1),
step2: this.getStepPercentage(2),
step3: this.getStepPercentage(3)
};
}
},
methods: {
getStepPercentage: function(stepNumber) {
if (stepNumber == 1) {
//depending on your requirements you will return
//a value between 0 and 100 that describe
//the completion status of the step 1
}
if (stepNumber == 2) {
//depending on your requirements you will return
//a value between 0 and 100 that describes
//the completion status of the step 2
}
if (stepNumber == 3) {
//depending on your requirements you will return
//a value between 0 and 100 that describes the
//completion status of the step 3
}
}
}
});
Also in your question, you have two Vue instances: one for which you load the components, and another one bound to the element with id #app. The one with the #app element is the one that will be managing your html from the blade file. The problem you will run into, once this code loads is that you are adding the components on the Vue instance that is not bound to your #app div, and therefore the Vue instance designated for managing your #app element will not have access to them. So I suggest using only one instance of Vue like in the example above unless you have a good reason for using more
Lastly, I would advise you against wrapping your 'vs-wizard' tag element with 'vs-toast', unless you are trying to display the wizard in your toast, which I am not sure is possible.
You can do something like this instead:
<div id="app">
<vs-toast></vs-toast>
<vs-wizard :current-index.sync="currentStep">
<vs-wizard-step
title="Personal Information"
description="Enter your details"
:progress="progress.step1"
icon="person">
</vs-wizard-step>
<vs-wizard-step
title="Payment"
description="Pay with credit card or Paypal"
:progress="progress.step2"
icon="credit-card">
</vs-wizard-step>
<vs-wizard-step
title="Confirmation"
description="Your order details"
:progress="progress.step3"
:disable-previous="true"
icon="check">
</vs-wizard-step>
</vs-wizard>
</div>

Related

How do I create a Vue 3 custom element, including child component styles?

I tried Vue's defineCustomElement() to create a custom element, but the child component styles are not included in the shadow root for some reason.
I then tried to manually create my shadow root using the native Element.attachShadow() API instead of using defineCustomElement() (based on a Codesandbox), but then no styles were loaded at all:
Code: main.js:
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
let treeHead = document.querySelector("#app");
let holder = document.createElement("div");
let shadow = treeHead.attachShadow({ mode: "open" });
shadow.appendChild(holder);
createApp(App).use(store).use(router).mount(holder);
Code vue.config.js:
module.exports = {
chainWebpack: (config) => {
config.module
.rule("vue")
.use("vue-loader")
.loader("vue-loader")
.tap((options) => {
options.shadowMode = true;
return options;
});
config.module
.rule("css")
.oneOf("vue-modules")
.use("vue-style-loader")
.tap((options) => {
options.shadowMode = true;
return options;
});
config.module
.rule("css")
.oneOf("vue")
.use("vue-style-loader")
.tap((options) => {
options.shadowMode = true;
return options;
});
},
};
Code package.json:
{
"name": "shadow-root",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"vue": "^3.2.20",
"vue-loader": "^16.8.2",
"vue-router": "^4.0.0-0",
"vue-style-loader": "^4.1.3",
"vuex": "^4.0.0-0"
},
"devDependencies": {
"#vue/cli-plugin-router": "~4.5.0",
"#vue/cli-plugin-vuex": "~4.5.0",
"#vue/cli-service": "~4.5.0",
"#vue/compiler-sfc": "^3.0.0",
"node-sass": "^4.12.0",
"sass-loader": "^8.0.2"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
How I can create a custom element with all its styles in the shadow root?
That Vue config is not necessary in Vue 3. It was only needed by the dev server in Vue 2 to render the styles in custom elements.
Using defineCustomElement() is the recommended way to register custom elements. However, there's an open issue when using defineCustomElement(), where nested component styles are not rendered at all (#vuejs/vue-next#4462).
A workaround is to import all components as custom elements so that the styles are attached to the component definition instead of being appended to <head>, then insert those styles into the DOM upon mounting:
Enable vue-loader's customElement mode in vue.config.js:
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
options.customElement = true
return options
})
}
}
Alternatively, rename all component filename extensions from .vue to .ce.vue.
Create a utility function that wraps Vue's defineCustomElement() and does the following in a setup():
Create a temporary application instance that adds a mixin for the mounted and unmounted lifecycle hooks.
In the mounted hook, insert the component's own styles from this.$.type.styles into the DOM in a <style> tag. Do the same with the component definitions from the this.$options.components map.
In the unmounted hook, remove the <style> tag that was inserted from mounted.
Copy the temporary application instance's _context into the current application context from getCurrentInstance().
Return a render function for the component.
// defineCustomElementWithStyles.js
import { defineCustomElement as VueDefineCustomElement, h, createApp, getCurrentInstance } from 'vue'
const nearestElement = (el) => {
while (el?.nodeType !== 1 /* ELEMENT */) el = el.parentElement
return el
}
export const defineCustomElement = (component) =>
VueDefineCustomElement({
setup() {
const app = createApp()
1️⃣
app.mixin({
mounted() {
const insertStyles = (styles) => {
if (styles?.length) {
this.__style = document.createElement('style')
this.__style.innerText = styles.join().replace(/\n/g, '')
nearestElement(this.$el).prepend(this.__style)
}
}
2️⃣
insertStyles(this.$?.type.styles)
if (this.$options.components) {
for (const comp of Object.values(this.$options.components)) {
insertStyles(comp.styles)
}
}
},
unmounted() {
this.__style?.remove() 3️⃣
},
})
4️⃣
const inst = getCurrentInstance()
Object.assign(inst.appContext, app._context)
5️⃣
return () => h(component)
},
})
Edit public/index.html to replace the <div id="app"> with a custom element (e.g., named "my-custom-element"):
Before:
// public/index.html
<body>
<div id="app"></div>
</body>
After:
// public/index.html
<body>
<my-custom-element></my-custom-element>
</body>
Instead of createApp(), use the defineCustomElement() from above to create a custom element of your app:
Before:
// main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
After:
// main.js
import { defineCustomElement } from './defineCustomElementWithStyles'
import App from './App.vue'
customElements.define('my-custom-element', defineCustomElement(App))
demo

No get query sting data in react

I'm trying to get query string parameters tho, it's blank.
This is URL.
https://master.deeiswmgeowge.amplifyapp.com/?site=gfg&subject=react
Then, this.props is empty.
The below is the source.
import React, { Component } from "react";
// Importing Module
import queryString from 'query-string'
class App extends Component {
state = {
site: 'unknown',
subject: 'i dont know'
}
handleQueryString = () => {
// Parsing the query string
// Using parse method
console.log(`this.props`, this.props)
let queries = queryString.parse(this.props.location.search)
console.log(queries)
this.setState(queries)
}
render() {
return (
<div style={{ margin: 200 }}>
<p> WebSite: {this.state.site} </p>
<p> Subject: {this.state.subject} </p>
<button
onClick={this.handleQueryString}
className='btn btn-primary'>
click me
</button>
</div>
);
}
}
export default App;
"dependencies": {
"#testing-library/jest-dom": "^5.11.4",
"#testing-library/react": "^11.1.0",
"#testing-library/user-event": "^12.1.10",
"query-string": "^6.14.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.2",
"web-vitals": "^1.0.1"
},
This is the error image.
You're not using react router , thus no location parameter in props :
so you have two solution ,
1 whether adding react-router-dom and wrap your app with router , ( or using with router hook like export default withRouter(App))
2 or access directly window.location.search and get params with URLSearchParams
by example :
const urlParams = new URLSearchParams(window.location.search);
const site = urlParams.get('site');
const subject = urlParams.get('subject');
Need to pass the props like
onClick={()=> this.handleQueryString(this.props)}
and received like
handleQueryString(arg) {
....
}

React.js State is not defined in class component

I am using a class component without a constructor to initialize state. Today, every react app i have tried to create has given me an error
Line 4:3: 'state' is not defined no-undef
my code is
class Page extends Component {
state = {
pages: []
}
render() {
return(
<div>page</div>
);
}
}
export default Page;
the weird part is in my old react apps it works fine. but every new 'npx create-react-app <>' i have tried today all give me undefined unless i use a class constructor.
here are my dependencies
"dependencies": {
"#testing-library/jest-dom": "^5.11.9",
"#testing-library/react": "^11.2.5",
"#testing-library/user-event": "^12.7.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.3",
"web-vitals": "^1.1.0"
Seems there is an issue with React version 16.3.1
I was having this issue today and came to this thread. Finally, after upgrading my npm react version from 16.3.1 to 16.4.0, my code is free of this issue.
Class component should be like this. Reference link of documentation here
class Page extends Component {
constructor(props){
super(props);
this.state = {
pages: []
}
}
render() {
return(
<div>page</div>
);
}
}
export default Page;
import React from 'react'
class Page extends React.Component{
state = {
pages: []
}
render() {
return(
<div>page</div>
);
}
}
export default Page;

Uncaught TypeError: Vue.component is not a function

In OS X with Laravel/Homestead, I'm getting an error using Vue (v2.2.1). The component won't load and the console error is "Uncaught TypeError: Vue.component is not a function".
Full console error
Uncaught TypeError: Vue.component is not a function
at eval (eval at <anonymous> (app.js:321), <anonymous>:17:5)
at Object.<anonymous> (app.js:321)
at __webpack_require__ (app.js:20)
at app.js:64
at app.js:67
What is throwing me off is that if I make a change to app.js, the webpack does not update to reflect any changes. So I need to A) fix the issue above, and B) figure out how to get the webpack to show updates in the console.
Any help would be greatly appreciated! I'm a noob. Here is my code...
app.js file
Vue.component('video-upload', require('./components/VideoUpload.vue'));
const app = new Vue({
el: 'body'
});
VideoUpload.vue
<template>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Example</div>
<div class="panel-body">
This is an example
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
upload.blade.php
#extends('layouts.app')
#section('content')
<video-upload></video-upload>
#endsection
package.json
{
"private": true,
"scripts": {
"prod": "gulp --production",
"dev": "gulp watch"
},
"devDependencies": {
"bootstrap-sass": "^3.3.7",
"gulp": "^3.9.1",
"jquery": "^3.1.0",
"laravel-elixir": "^6.0.0-9",
"laravel-elixir-vue": "^0.1.4",
"laravel-elixir-webpack-official": "^1.0.2",
"lodash": "^4.14.0",
"video.js": "^5.11.6",
"vue": "^2.2.1",
"vue-resource": "^0.9.3"
}
}
After an update from laravel-mix 5.0.9 to laravel-mix 6.0.11 on a laravel 7 project it started to see this error on vue compiled views. I change the call the Vue package:
Use import Vue from 'vue' instead of window.Vue = require("vue"); worked for me.
import vue properly in your code using import keyword like this:
//import vue
import Vue from 'vue';
//register component
Vue.component('yourComponentName',require('./components/yourComponentName.vue').default);
//initialize vue
const app = new Vue({
el: '#app',
});
For any one who has the same issue and is not related to Laravel.
Hint: using Vue 3+
Register the component globally:
const MyComponent = {
// ... options ...
}
// if you do not have App component
Vue.createApp({}).component("my-component", MyComponent).mount("#app");
// if you have an App component
const App = {
// ... options ...
}
const app = Vue.createApp(App);
app.component("my-component", MyComponent);
app.mount("#app");
Please refer to Documentation for more info
1
Change your package.json
"laravel-elixir-vue-2": "^0.3.0"
And run
<!-- language: lang-js -->
npm install
OR
2
npm install laravel-elixir-vue-2 --save-dev
And then
Change your gulpfile.js like this
<!-- language: lang-js -->
var elixir = require('laravel-elixir')
require('laravel-elixir-vue-2');
CHECK YOUR CDN VUE VERSION. THEY CHANGED FROM VUE 2 TO VUE 3.
This scenarion happened here, we were using Vue 2 and our CDN changed the global script to Vue 3.
Vue 3 changed the "Vue.component" to "Vue.directive" which broke our application.
VUE.JS CDN changed the global script to Vue 3 which is not supported [Vue.component] any more.
Use Vue Version 2.6.14, this works for me (older apps)
https://v2.vuejs.org/v2/
window.Vue = require('vue').default;
const app = new Vue({
el: '#app',
});
<body>
<div id="app">.....</div>`
</body>
just add this
/*import Vue from 'vue/dist/vue'*/ before
/*require('./bootstrap');*/
require('./bootstrap');
import Vue from 'vue/dist/vue'
window.Vue = require('vue');
Vue.component('mainapp', require('./component/mainapp.vue').default);
const app = new Vue({
el:"#app",
});

Testing react-bootstrap with mocha and ES6/babel

I am trying to write a unit test of React and React-bootstrap components using Mocha.
All of my javascript is written in ES6, and I am using babel to transpile to ES5.
The files I am using are below.
After running npm install, I run npm test. This fails with the following output:
$ npm test
> # test /Users/tda0106/test/npm
> mocha --compilers jsx:babel-register simple-test.jsx
A simple test
1) "before all" hook: render and locate element
0 passing (34ms)
1 failing
1) A simple test "before all" hook: render and locate element:
AssertionError: expected null to exist
at Context.<anonymous> (simple-test.jsx:21:9)
npm ERR! Test failed. See above for more details.
TestUtils.renderIntoDocument is returning null for no reason that I can see. The TestUtil docs indicate that window and document must be defined before importing React, which is the point of test-dom.jsx.
I am certain that test-dom.jsx is loaded before React, because before I added the line setting global.navigator, React was throwing an error deep in its code trying to access that variable.
Any idea what I need to do to make this work?
package.json
{
"dependencies": {
"react": "^15.0.1",
"react-bootstrap": "^0.28.5",
"react-dom": "^15.0.1"
},
"scripts": {
"test": "mocha --compilers jsx:babel-register simple-test.jsx"
},
"devDependencies": {
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babelify": "^7.2.0",
"chai": "^3.5.0",
"jsdom": "^8.4.0",
"mocha": "^2.4.5",
"react-addons-test-utils": "^15.0.1"
}
}
test-dom.jsx
// React needs the basic dom objects defined before it is imported.
// And babel moves the imports before the rest of the code.
// So the dom setup needs to be in its own file and imported.
import jsdom from 'jsdom';
const document = jsdom.jsdom("hello world");
const window = document.defaultView;
// A super simple DOM ready for React to render into
// Store this DOM and the window in global scope ready for React to access
global.document = document;
global.window = window;
global.navigator = {userAgent: 'None'};
export default { document: document, window: window };
simple-test.jsx
import TestDom from './test-dom.jsx';
import { expect } from 'chai';
import React from 'react';
import { Panel } from 'react-bootstrap';
import TestUtils from 'react-addons-test-utils';
const Map = () => (
<Panel>A map </Panel>
);
describe('A simple test', () => {
before('render and locate element', () => {
const renderedComponent = TestUtils.renderIntoDocument(
<Map />
);
expect(renderedComponent).to.exist; // This fails
});
it('test something', () => {
expect(1+1).is('true');
});
});
.babelrc
{
"presets": [
"es2015",
"react"
]
}

Categories

Resources