React JS: How to call a function to return JSX code? - render

I'm new to react and I'm trying to create a JSX element in a function. The JSX should dynamically add 2 buttons each time when you click the button. However, when render() calls this function, it isn't rendering the element (white page in browser).
How would I go about fixing this? Any help would be appreciated. Thanks!
class Test extends Component {
constructor(){
super();
this.state = {
fields: [{key:'key', val:'val'}]
}
this.renderPanel = this.renderPanel.bind(this);
}
addField() {
this.setState({
fields: [...this.state.fields, {key:'key', val:'val'}],
})
}
renderPanel(){
return <div>
<form>
<div id="testingAPanel">
{()=>this.state.fields.map((input,index) => {return(
<tr>
<input type='button' id={index} value={input.key} />
<input type='button' id={index} value={input.val} />
<br/>
</tr>
)}
)}
</div>
</form>
<button onClick={ () => this.addField() }>
CLICK ME TO ADD AN INPUT
</button>
</div>
}
render() {
return (
<div class = 'test'>
{()=>this.renderPanel()}
</div>
);
}
}
export default Test;```

class App extends React.Component {
buttonClick(){
console.log("came here")
}
subComponent() {
return (<div>Hello World</div>);
}
render() {
return (
<div className="patient-container">
<button onClick={this.buttonClick.bind(this)}>Click me</button>
{this.subComponent()}
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
it depends on your need, u can use either this.renderIcon() or bind this.renderIcon.bind(this)
UPDATE
This is how you call a method outside the render.
buttonClick(){
console.log("came here")
}
render() {
return (
<div className="patient-container">
<button onClick={this.buttonClick.bind(this)}>Click me</button>
</div>
);
}
The recommended way is to write a separate component and import it.

Related

Add parameter at onClose in relation Modal

Goal:
When you press the button named "yes 1", the value should contain "yes yes" and in the end the console.log should display "test yes yes".
When you press the button named "yes 2", the value should contain "no no" and in the end the console.log should display "test no no".
The display of the value "test yes yes" or "test no no" take place at index.tsx.
The execution or the decision take place at ModalForm.tsx.
Problem:
In technical perspectiv, tried to find a solution by using this code onClick={props.onClose("yes yes")} but it doesn't work.
How do I solve this case?
Stackblitz:
https://stackblitz.com/edit/react-ts-rpltpq
Thank you!
index.html
<div id="root"></div>
<!-- Latest compiled and minified CSS -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<!-- Latest compiled JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js"></script>
index.tsx
import React, { Component, useState, useEffect } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import { ModalForm } from './ModalForm';
import './style.css';
interface dddd {
clientid: string | undefined;
idid: number;
}
const getTest = () => {
console.log('test');
};
const App = () => {
const [clientiddd, setClientid] = useState('ddfdf');
const [idid, setIdid] = useState(0);
return (
<div>
<button
data-bs-toggle="modal"
data-bs-target="#myModalll"
className={'btn btn-outline-dark'}
>
{'data'}
</button>
<br />
<ModalForm clientid={clientiddd} onClose={getTest} />
</div>
);
};
render(<App />, document.getElementById('root'));
ModalForm.tsx
import React, { Component } from 'react';
interface ModalProps {
clientid: string | undefined;
onClose: () => void;
}
export const ModalForm = (props: ModalProps) => {
return (
<div
className="modal"
id="myModalll"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h4 className="modal-title">T</h4>
<button
type="button"
className="btn-close btn-close-black"
data-bs-dismiss="modal"
onClick={props.onClose}
></button>
</div>
<div className="modal-body">
TITLE:
<br />
<button
type="button"
data-bs-dismiss="modal"
onClick={props.onClose}
>
yes 1
</button>
<button
type="button"
data-bs-dismiss="modal"
onClick={props.onClose}
>
yes 2
</button>
<br />
</div>
</div>
</div>
</div>
);
};
It's somewhat hard to understand your question, but let me try.
onClick={props.onClose('yes yes')}
What this code does is that it calls props.onClick with yes yes as an argument and assigns the returned value as the onClick listener.
Assume the props.onClose is this:
function onClose() {
console.log('test')
}
What it does here is that it calls this function (it logs test to the console) but since this function is not returning anything, it passes undefined as the onClick here.
If instead your function was this:
function onClose(result) {
return function () {
console.log('test', result)
}
}
Now it would call props.onClose with yes yes and it would return a function. This anonymous function would be passed as the onClick event listener and when you click, it would call that so there would be test yes yes logged only after clicking.
You can as well do it differently, keep your onClose function as it was but introduce result:
function onClose(result) {
console.log('test', result)
}
but now you have to pass this function instead of calling it:
onClick={() => props.onClose('yes yes')}
As you can see, there will always be one anonymous function somewhere in there, it's just a question of where that function is and what is called when. Hope this explanation helps.
https://stackblitz.com/edit/react-ts-nw6upt?file=index.html
index.html
<div id="root"></div>
<!-- Latest compiled and minified CSS -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<!-- Latest compiled JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js"></script>
index.tsx
import React, { Component, useState, useEffect } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
import { ModalForm } from './ModalForm';
interface dddd {
clientid: string | undefined;
idid: number;
}
const getTest = (result: string) => {
console.log('testff ' + result);
};
const App = () => {
const [clientiddd, setClientid] = useState('ddfdf');
const [idid, setIdid] = useState(0);
return (
<div>
<button
data-bs-toggle="modal"
data-bs-target="#myModalll"
className={'btn btn-outline-dark'}
>
{'data'}
</button>
<br />
<ModalForm clientid={clientiddd} onClose={getTest} />
</div>
);
};
render(<App />, document.getElementById('root'));
ModalForm.tsx
import React, { Component } from 'react';
interface ModalProps {
clientid: string | undefined;
onClose: (result: string) => void;
}
export const ModalForm = (props: ModalProps) => {
return (
<div
className="modal"
id="myModalll"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h4 className="modal-title">T</h4>
<button
type="button"
className="btn-close btn-close-black"
data-bs-dismiss="modal"
onClick={() => props.onClose('ccc')}
></button>
</div>
<div className="modal-body">
TITLE:
<br />
<button
type="button"
data-bs-dismiss="modal"
onClick={() => props.onClose('aaa')}
>
yes 1
</button>
<button
type="button"
data-bs-dismiss="modal"
onClick={() => props.onClose('bbb')}
>
yes 2
</button>
<br />
</div>
</div>
</div>
</div>
);
};

Get all values of custom input inside v-for vuejs

I created a vuejs custom input that I wanted to use to dynamically display inputs by using props within the custom input. I haven't shown them here because it would be too long.
By clicking on the submit button, which is also part of the custom input, I wanna be able to get the values of each input, but for some reason, I have only been able to get the value of the last input.
What am I doing wrong?
Custom input:
<template>
<div class="form-input">
<label :label="label" :for="name" v-if="label && type !='submit' ">{{label}} <span v-if="required">*</span></label>
<a v-if="multiple" href="#" class="btn">Upload</a>
<input v-model="inputVal" :multiple="multiple" v-if="type != 'textarea' && type != 'submit'" class="form-control" :required="required" :class="classes" :type="type" :name="name" :placeholder="placeHolder">
<textarea v-model="inputVal" :multiple="multiple" v-else-if="type != 'submit'" class="form-control" :required="required" :class="classes" :type="type" :name="name" :placeholder="placeHolder"></textarea>
<button :multiple="multiple" :name="name" v-else type="submit">{{label}}</button>
</div>
</template>
<script>
export default {
name: "Input",
data () {
return {
inputVal: null
}
},
watch: {
inputVal: {
handler: function(newValue, oldValue) {
this.$emit('input', newValue);
},
deep: true,
}
}
}
</script>
Form where custom input is used:
<template>
<div class="form container">
<form v-on:submit.prevent="sendMail" method="post" class="d-flex row shadow bg-dark border-right border-dark">
<h3 class="col-12">Contact me</h3>
<Input v-model="formInput" v-for="input in inputs" v-bind:key="input.name" :label="input.label" :multiple="input.multiple" :type="input.type" :name="input.name" :class="input.classes" :required="input.required"></Input>
</form>
</div>
</template>
<script>
import Input from "../components/Input";
export default {
name: "Contact",
components: {Input},
data() {
return {
formInput: null,
}
},
methods: {
sendMail () {
console.log(this.formInput);
}
}
}
</script>
The issue I see in your code is, you are using only one variable "formInput" ( in case of Contact component ) and "inputVal" ( in case of Input component ) but you have number of input fields from where you need data right.
The simplest way to deal with these kind of cases is to create a datastructure and loop through that.
For eg.
// Contact component ( i am making it simple to make you understand the scenario )
<template>
<div class="form container">
<form v-on:submit.prevent="sendMail" method="post" class="d-flex row shadow bg-dark border-right border-dark">
<h3 class="col-12">Contact me</h3>
<!-- we are looping through our data structure and binding each inputVal to this input -->
<input v-for="(input, i) in formInputs" :key="i" v-model="input.inputVal">
</form>
</div>
</template>
<script>
import Input from "../components/Input";
export default {
name: "Contact",
components: {Input},
data() {
return {
formInputs: [
{inputVal: ''},
{inputVal: ''},
{inputVal: ''},
],
}
},
methods: {
sendMail () {
// You can extract the data from formInputs as per your need
}
}
}
</script>

Data not showing in my console.log in vue

In my vue app I have 2 methods, one method gets some data from my laravel backend and the second one needs to be able to grab it so that I can use it in that method.
What I'm struggling with is that the second method isn't grabbing the data.
Here is my code
<template>
<app-layout>
<div class="content-wrapper" style="margin-left: 0;">
<div class="content">
<div class="container">
<div class="row pt-5">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-lg-12">
Some data will show here
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</app-layout>
</template>
<script>
import AppLayout from '#/Layouts/AppLayout'
export default {
components: {
AppLayout,
},
data() {
return {
testData: ''
}
},
methods: {
firstMethod() {
axios.get('/api/get-data').then(response => {
this.testData = response.data;
});
},
secondMethod(){
console.log(this.testData);
}
},
mounted() {
this.firstMethod();
this.secondMethod();
}
}
</script>
your running both function in mount function so both run at same time and secondMethod() executed 1st at that time your this.testData is not set so you can use async and await to wait to finish firstMethod() then run secondMethod()
which will be like below code
<template>
<app-layout>
<div class="content-wrapper" style="margin-left: 0">
<div class="content">
<div class="container">
<div class="row pt-5">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-lg-12">
Some data will show here
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</app-layout>
</template>
<script>
import AppLayout from "#/Layouts/AppLayout";
export default {
components: {
AppLayout,
},
data() {
return {
testData: "",
};
},
methods: {
async firstMethod() {
const { data } = await axios.get("/api/get-data");
this.testData = data;
},
secondMethod() {
console.log(this.testData);
},
},
async mounted() {
await this.firstMethod();
this.secondMethod();
},
};
</script>
You can try calling firstMethod in created() hook instead of mounted. In my opinion you do not need a method for modifying incoming data. Use watch instead:
watch: {
// whenever question changes, this function will run
testData: function (newValue) {
// do what transformation you need here
}
}
Watch hooks run when value of variable changes, so it should run when it is assigned.
The problem that you dont see the console log is because even if you execute first the first method, it's actually executed after the second method because takes more time to be resolved.
Try the below please, inside first method i added after then to execute the second method which means that that the first method would be resolved, thus we will have the api response.
In case you continue seeing nothing from console log then there is an issue with the api endpoint.
mounted() {
this.firstMethod();
},
methods: {
firstMethod() {
axios.get('/api/get-data').then(response => {
this.testData = response.data;
this.secondMethod();
});
},
secondMethod(){
console.log(this.testData);
}
},

Owl carousel spits out a single item instead of a carousel

I am trying to make a carousel that shows a list of new tutors in a specific area from latest first. I am using laravel 5.6, vue.js and owl carousel.
Below I am using axios to retrieve from the database, and call owl-carousel
<script>
export default {
props: {
areaId: null,
},
data () {
return {
NewTutors: {}
}
},
methods: {
getNewTutor () {
var that = this;
axios.get( '/' + this.areaId + '/home/new').then((response) => {
that.NewTutorss = response.data;
})
.catch(error => {
console.log(error)
this.errored = true
});
}
},
mounted () {
this.getNewTutor();
}
}
$(document).ready(function() {
$('#NewHustles').owlCarousel();
});
</script>
and here and try and loop through each new tutor in a carousel.
<div class="owl-carousel owl-theme owl-loaded" id="NewTutors">
<div class="owl-stage-outer">
<div class="owl-stage">
<div class="owl-item" v-for="NewTutor in NewTutors>
<div class="card">
<div class="card-header">
{{NewTutor.name}}
</div>
<div class="card-body">
<div>
{{NewTutor.area.name}}
</div>
<div>
Image goes here
</div>
<div>
{{NewTutor.user.first_name}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
I get all the cards, with the correct data passed through, but instead of a single row carousel, I get a big blob of cards that move as if there was only one item. I have tried Vue.nexttick, and playing around with a few other things, but nothing seems to work quite right.
Thank you for your help.

vue2 call a parent function using $emit from component

i'm trying to call a parent methods from child component, but it seems not working.. here the code:
index.html
<div class="percorso"v-on:removeall="pathlengthTozero()">
</div>
component
Vue.component('lista-percorso', {
template:`
<div class="col-lg-2 col-xs-2">
<div class="removeall pull-right" v-on:click="removeall()"></div>
</div>`,
methods:{
removeall : function(){
this.listaSelezionati = [];
this.$emit('removeall');
}
}
parent method
pathlengthTozero : function(){
il_tuo_percorso = [''];
}
seems that "pathlengthTozero" is not called on emit which is the correct way to use it?
You need to put this v-on:removeall="pathlengthTozero" to the component <lista-percorso> like below,
<lista-percorso v-on:removeall="pathlengthTozero"></lista-percorso>
and this.$emit will able to fire the parent method.
Sample Demo:
Vue.component('lista-percorso', {
template:`
<div class="col-lg-2 col-xs-2">
<div class="removeall pull-right" v-on:click="removeall()">xxxxxxxxxx</div>
</div>`,
methods:{
removeall : function(){
this.listaSelezionati = [];
this.$emit('removeall');
}
}
})
var App = new Vue({
el: '#app',
methods:{
pathlengthTozero : function(){
alert('hello');
il_tuo_percorso = [''];
}
}
});
<script src="https://unpkg.com/vue"></script>
<div id="app">
<div class="percorso" ></div>
<lista-percorso v-on:removeall="pathlengthTozero"></lista-percorso>
</div>
you should put the event listener on the child conponent where it is used
<div class="percorso">
<lista-percorso v-on:removeall="pathlengthTozero"></lista-percorso>
</div>

Resources