react not receiving prop from html - laravel

I have a react component in a file named ts.js:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
export default class Ts extends React.Component {
constructor(props) {
super(props);
var expected = {
lowercase:'Onlylowercase',
snakeCase:'justSnakeCase',
ProperCase: 'AndProperCase'
};
console.log("expected:",expected);
console.log("props:",props);
console.log("this.props",this.props);
console.log("props.lowercase",props.lowercase);
this.state={'lowercase':this.props.lowercase};
};
render() {
return NULL;
}
}
if (document.getElementById('ts')) {
ReactDOM.render(<Ts />, document.getElementById('ts'));
}
I also have a html page from where this is called:
<html>
<head>
<title>My TS</title>
</head>
<body>
<Ts lowercase="onlylowercase" id="ts" snakeCase="justSnakeCase" ProperCase="AndProperCase">
</Ts>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
My issue is I can't get the values lowercase="onlylowercase" id="ts" snakeCase="justSnakeCase" ProperCase="AndProperCase" recognised as props in the constructor. I need to pass in some stuff from the html to populate the initial state of the component.
When I open the HTML with Chrome console open I get:
expected: {lowercase: "Onlylowercase", snakeCase: "justSnakeCase", ProperCase: "AndProperCase"}
props: {}
__proto__: Object
or it is this.props?: {}
__proto__: Object
props.lowercase undefined
this.props.lowercase undefined
undefined
undefined
I am expecting props to be a javascript object with properties of lowercase, snakeCase and ProperCase, like the var expected.
I don't think I need to use componentWillReceiveProps - as I am trying to follow the pattern describe in the documentation here:
https://reactjs.org/docs/react-component.html#constructor
and pass in props as html attributes as described here:
https://reactjs.org/docs/components-and-props.html
I have excluded from this post the detail of the node modules and javascript includes - as the Ts component's constructor is being called which demonstrates the Ts class is "there" and my npm config is OK - it is including react and other required modules. The {{ asset() }} function is a Laravel function. The html is part of a blade template in a Laravel app.
Can anyone see what I am doing wrongly?

Your syntax is wrong. React doesn't creat a new html tag like "". You only can use tag in react component. So the right syntax is in html replace
<Ts lowercase="onlylowercase" id="ts" snakeCase="justSnakeCase" ProperCase="AndProperCase">
</Ts>
To <div id="ts"></div>
and go add to before
<script>
var lowercase="whatever";
var snakeCase="snakeCase";
...
</script>
And change to
if (document.getElementById('ts')) {
ReactDOM.render(<Ts lowercase={lowercase} snakeCase={snakeCase} />, document.getElementById('ts'));
}
ReactDOM will find a dom with id is "ts" and replace it by your ts component.

Related

laravel livewire $wire is not defined

I think I have all my imports right, but I'm getting a $wire is not defined error.
This is at the bottom of my master layout blade file:
#livewireScripts
<script src="{{ asset('js/app.js') }}"></script>
#stack('plugin-scripts')
#stack('custom-scripts')
In my livewire component I have this:
#push('custom-scripts')
<script>
$(document).ready(function() {
console.log($wire.find($('#my-div').attr('id')));
});
</script>
#endpush
I was reading that $wire is an Alpine directive, and here's where I'm including Alpine. I can also type Alpine in the console and it is registered, so I believe that's working.
in my bootstrap.js:
import Alpine from 'alpinejs'
window.Alpine = Alpine
window.Alpine.start()
Also if I type Livewire in the console, it returns the Livewire object, so that seems to be getting loaded correctly as well. However, I added this bit to my code and it did nothing:
document.addEventListener('livewire:load', function() {
console.log('livewire loaded'); // Your JS here.
});

How to use Alpine.data() in #push within Laravel Blade components?

With Alpine.js 2 it was possible to develop Blade components with the following structure:
...
<div x-data="myApp()">
...
#once
#push('child-scripts')
<script>
function myApp() {
return {
...
}
}
</script>
#endpush
#endonce
This was great in that it allowed all the code for the component to be defined together.
In Alpine.js 3 this approach of defining functions is deprecated (https://alpinejs.dev/upgrade-guide#alpine-data-instead-of-global-functions). Instead, they should be defined like this:
...
<div x-data="myApp">
...
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('myApp', () => ({
...
}))
})
</script>
However, it states "you need to define Alpine.data() extensions BEFORE you call Alpine.start()". This suggests that with the new approach it is impossible (or at best unreliable) to use #push to add data functions for use in Blade components and, therefore, impossible to keep all the code for a Blade component together.
My code all works fine with Alipne 3, if I use the deprecated approach. If I try to include the new syntax data function via #push, I get "myApp is not defined" JS error from my Blade component.
I am using Alpine.js 3.9 installed as an NPM module. I have also tried using Alpine.js 3 via <script src="https://unpkg.com/alpinejs#3.x.x/dist/cdn.min.js" defer></script>. The result is the same in both cases.
Is there a way to keep all the code together in the Blade component?
UPDATE 25.02.2022
It seems I need to provide more details of what I am doing so here they are.
The relevant bits of my app.blade.php are:
<head>
...
<script src="{{ asset('js/app.js') }}" defer></script>
#livewireStyles
...
</head>
<body>
// HTML/Blade stuff here
#livewireScripts
#stack('child-scripts')
</body>
My app.js is like:
import Alpine from 'alpinejs'
require('./bootstrap');
window.Alpine = Alpine
Alpine.start();
I have also tried:
require('./bootstrap');
import Alpine from 'alpinejs'
window.Alpine = Alpine
Alpine.start();
My Blade component is like this:
...
<div x-data="myApp">
...
#once
#push('child-scripts')
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('myApp', () => ({
...
}))
})
</script>
#endpush
#endonce
When I access a page that uses the Blade component, I get "Uncaught ReferenceError: myApp is not defined".
If I revert my Blade component to the old syntax (as follows) it works with no errors:
...
<div x-data="myApp()">
...
#once
#push('child-scripts')
<script>
function myApp() {
return {
...
}
}
</script>
#endpush
#endonce
The only difference between the working and failing versions is the way in which myApp is defined. The deprecated method works but, with the new method, it doesn't.
Not sure why you would think that using #push is unreliable.
Since the #push directive (like any other blade directive) is evaluated by the blade engine on the server-side, by the time the page loads, anything you push is already there on the page.
One thing to note is that it is important to defer the execution of the javascript assets so that it is executed after the document has been parsed. You can do that by adding a defer attribute like so:
<!DOCTYPE html>
<html>
<head>
...
<script src="{{ mix('js/app.js') }}" defer></script> {{-- or CDN here --}}
</head>
<body>
...
#stack('scripts')
</body>
</html>
// resources/js/app.js
import Alpine from 'alpinejs'
window.Alpine = Alpine
Alpine.start()
I'm already using Alpine v3 this way without any issues.

Passing and binding img src from props in Vue.js

I am trying to display an image with the img tag by using a path from props for the src attribute.
I've tried changing the path with #, using the whole path with src, adding ../assets/ in the component and only passing the file name (orange.png) as props.
I always get the default broken image displayed.
When inspecting in the browser, the path seems fine.
When I display the image directly, I can see that the path is resolved to some different path <img data-v-1212d7a4="" src="/img/orange.7b71a54c.png">.
Edit:
Additionally I tried this post Can't dynamically pass relative src path for imgs in Vue.js + webpack ,
where using <img :src="require(picture_src)" /> is given as an answer.
This leads to an error: Error in render: "Error: Cannot find module '../assets/orange.png'"
(Edit2:
This answer in the end worked for me in the end as described in my answer post.)
The same error occurs with the similar webpack method using let images = require.context('../assets/', false, /\.png$/) in my script part, as the answer on this post Can't dynamically pass relative src path for imgs in Vue.js + webpack .
I am new to Vue.js, so I don't exactly know what is happening or how to search for this or it might not have anything to do with what I'm originally trying.
I am able to display my image when I pass the path directly, like this
<img src="../assets/orange.png"/>
Now I'd actually like to pass it to my component in the props and then, inside the component, display it reading the path from props.
Component
<template>
<div>
<img :src=picture_src />
<div class="pic_sub">{{pic_desc}}</div>
</div>
</template>
<script>
export default {
name: 'PictureCard',
props: {
picture_src: String,
pic_desc: String
}
}
</script>
Using the component:
<template>
<div>
<PictureCard pic_desc='some description text' picture_src='../assets/orange.png' />
</div>
</template>
<script>
import PictureCard from './components/PictureCard.vue'
export default {
name: 'app',
components: {
PictureCard
}
}
</script>
If it is possible, I'd love to display my from a path that is passed through the component's props.
Otherwise I'd love to know some other solutions, work-arounds or knowledge on best practices in this case.
This worked for me
<img :src="require(`#/assets/img/${filename}`)">
where filename is passed in as a String prop e.g. "myImage.png".
Make sure you use the path specific to your project.
Source: https://github.com/vuejs-templates/webpack/issues/450
Note: # is a webpack alias for /src that is set by default in Vue projects
After some research, I understand that my problem has to do with webpack and resolving filepaths. I used a modified version from this answer:
Vue.js dynamic images not working
and this answer:
Can't dynamically pass relative src path for imgs in Vue.js + webpack
Since the link in the second answer was dead, here's an active link to require.context documentation:
https://webpack.js.org/guides/dependency-management/#requirecontext
My mistake when trying the second link's answer was that I returned only orange.png as the path, while I needed to add ./ at the beginning.
My working picture component now looks like this.
<template>
<div>
<img :src="resolve_img_url(picture_src)" />
<div class="pic_sub">{{pic_desc}}</div>
</div>
</template>
<script>
export default {
name: 'PictureCard',
props: {
picture_src: String,
pic_desc: String
},
methods: {
resolve_img_url: function (path) {
let images = require.context('../assets/', false, /\.png$|\.jpg$/)
return images("./"+path)
}
}
}
</script>
I edited the regular expression to match .png and .jpg file endings. Therefore passing the prop looks like this now
<PictureCard picture_src='orange.png' pic_desc='some picture description'/>
This works for me:
This is how i use my Componenent.
<image-element
:imageSource="require('#/assets/images/logo.svg')">
</image-element>
My Image Component:
<template>
<div>
...
<img v-bind:src=imageSource />
...
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import { Component, Prop } from 'nuxt-property-decorator'
#Component({
components: {
.....
}
})
export default class extends Vue {
...
#Prop({ default: '' }) imageSource!: String
...
}
</script>
Newer solution:
The 'require()'-method does not work when using Vite.
I got this error: ReferenceError: require is not defined.
This is how I solved it without 'require()' and with composition API:
From parent component:
<ChildComponent icon-filename="icon.svg" />
ChildComponent:
<template>
<div>
<img :src="getImageUrl()">
</div>
</template>
<script setup lang="ts">
import {defineProps} from "vue";
const props = defineProps({
iconFilename: String
})
function getImageUrl() {
// This path must be correct for your file
return new URL(`../assets/icons/${props.iconFilename}`, import.meta.url)
}
</script>
this is my favorite super simple way to do it. It can easily be reused in any file in any folder in my project. Just pass the actual path as a string from the perspective of the parent:
//some file
<ParentA>
<ImageComponent
myImagePath="../../../../../myCat.png"
/>
</ParentA>
//some other file in a different folder in my project
<ParentB>
<ImageComponent
myImagePath="../../myCat.png"
/>
</ParentB>
//child component file
<template functional>
<div>
<img :src="props.myImagePath">
</div>
</template
Thats all not working for me :D
The template File is wrong!
you need to add ":" before you set your prop.
thats how i should use the PictureCard
<PictureCard :picture_src="require('orange.png')"
pic_desc='some picture description'/>
and thats how my PictureCard should look like:
<template>
<div>
<img v-bind:src="picture_src" />
</div>
</template>
export default class PictureCard extends Vue {
#Prop({ default: require("#/assets/orange.svg") }) img!: string
}
so in case no prop is setted, so i added a default prop too.
and yes i only used the image.

How to pass custom nativescript-Vue component to custom child Component

I would like to add a dynamic child component to a parent component using Nativescript-Vue. For example:
<template>
<MyParentComponent>
<MyChildComponent :foo="foo"></MyChildComponent>
</MyParentComponent>
<template>
<script>
import MyParentComponent from './components/MyParentComponent';
import MyChildComponent from './components/MyChildComponent';
export default {
components: {
MyParentComponent,
MyChildComponent
},
data: function(){
return {
foo: ''
}
}
}
</script>
I think I need to define a slot in the parent component where the child component should be inserted, but I don't know how this should be done.
Any ideas?
In MyParentComponent's template you need to add a <slot /> tag, that's where Vue will insert the content.
Read more about slots, and what they can do in the Vue docs:
https://v2.vuejs.org/v2/guide/components.html#Content-Distribution-with-Slots

use parse react query results as an html tag attribute

This is my first time asking a question so I am a true SO newbie. I am currently working on a mobile app and I am using Parse React and Ratchet to build it. I have read the React documentations on FB github and apparently do not understand all enough to solve some problems. One of my problems is using the results of a Parse Query in the observe function of the declared ParseComponent as a value of a rendered react component, which in turn attempts to render the passed value as HTML. Below is the parent object:
export default class CategoryPage extends ParseComponent
{
observe(props,state){
return{
category: new Parse.Query('BusinessCategory').equalTo("objectId", this.props.categoryId)
};
}
render() {
return (
<div>
<Header text={this.data.category.objectId} back="true"/>
<div className="content">
<BusinessList categoryId={this.data.category.objectId}/>
</div>
<NavBar />
</div>
);
}
};
Notice I am passing the objectId of the category found in the Query as a text attribute of the Header React component. I am expecting Header as a child to use the passed property as follows:
var Header = React.createClass({
render: function () {
return(
<header className="bar bar-nav">
<h1 className="title">{this.props.text}</h1>
</header>
);
}
});
However the h1 is not rendering anything! I am thinking that this.data.category.objectId is a string and therefore should be rendered in the h1 tag as a string.
I do appreciate your answers very much.

Resources