React Component won't render after Jquery Ajax Call - javascript

I have a simple jquery ajax that fetch inline HTML code from an API
$.ajax({
url: url,
headers: { 'Accept': 'application/javascript' },
dataType: 'html',
beforeSend: function(){
$('.load-more').slideDownThenFadeIn(100);
}
})
.done(function(data) {
$('#container').append(data);
});
It's a simple button not built with React
<a class="btn load-more" href="javascript:void(0)">Load More</a>
The Ajax call invokes the API to render html code back to the server...
It renders back the html code below
<div data-react-class=\"My.React.Base.PostButton\" data-react-props=\"{"buttonText":"Contact me","buttonClass":"btn btn-clear btn-block","business":{"id":86055,"business_name":"Buy Plan","mobile_phone":"0412 345 678"},"cta":"card","slideTitle":null,"showPostJobExclusively":true,"showToAll":false,"CallCustomer":false}\"></div>
but react component did not render...
I'm actually expecting the react component to be rendered, but below is missing after appending the ajax data
<a data-reactroot="" class="btn btn-clear btn-block" href="#"><span><!-- react-text: 3 -->Contact me<!-- /react-text --></span></a>
Am I missing something here?
EDIT:
<div class="card"><div class="col-xs-6 pr8"><div data-react-class="SS.React.Base.ProfileJobPostButton" data-react-props="{"buttonText":"Contact me","buttonClass":"btn btn-clear btn-block","business":{"id":129679,"business_name":"IMC Cleaning Services","mobile_phone":"6197877882"},"cta":"business_directory_card","slideTitle":null,"showPostJobExclusively":true,"showPostJobToAll":false,"showCallBusiness":false}"></div></div>
the React component from API looks something like below
render() {
return(
<a className={this.props.buttonClass} href="#" onClick={this.handleOnClick}>
{
this.state.loading ?
<My.React.Base.Spinner spinnerColour='white-spinner' />
:
<span>
{this.props.buttonText}
{this.props.withArrow && <i className="ficon-arrow-right-shaft pl10" />}
</span>
}
</a>
)
}

You are using a wrong approach. First of all you should not force render html code inside the react components. so usually APIs should return data and html should be the part of react component.
But anyways if you are using this approach you should use dangerouslySetInnerHtml attribute of react refer the link https://facebook.github.io/react/docs/dom-elements.html
Thats the react way of modifying dom or appending html to dom nodes' html.
Also you can modify the component after the component is mounted. So if you are making API call after your component has mounted which usually is the case, you can store the html in state, and using the aforesaid attribute dangerouslySetInnerHTML, you can set its value to state variable.

Related

Pass down data trough router link to my axios api call

I wanted to ask if it is possible to pass data to my methods via router link in vue. I am a beginner who made a .net core api with the help of a youtube video and then call it in a html with vue/javascript. Now I have different components and each one is a separate js file which I don't find very nice because actually in all of them the same thing happens.
For example (html router link):
<li class="nav-item m-2">
<router-link class="btn btn-light btn-outline-primary" to="/home">GM10</router-link>
</li>
goes to home compnent which calls the api here and stores the json in chashier:
data(){
return{
chasier:[],
}
},
methods:{
refreshData(){
axios.get(variables.API_URL+'Store10')
.then((response)=>{
this.chasier=response.data
})
}
},
Second router link would be
<router-link class="btn btn-light btn-outline-primary" to="/GM11">GM11</router-link>
which goes to component gm11 but home and gm11 are the same except in gm11 it says axios.get(variables.API_URL+'Store11')
I would like to use only one js so that the router link "to" is the same for both but depending on which router link you press the url ending changes.
I tried already some stuff from the web but I nothing is really working. I lack of understanding and only the Youtube Video was not enough

Getting data from declared component in vue

Currently trying to wrap my head around Vue and templates.
I read that you pass data from child -> parent with $emit()
app.js
Vue.component('tweet-postbox', require('./components/tweetPostBox.vue').default);
const app = new Vue({
el: '#app',
methods: {
addTweet (tweet) {
//from the tweetPostBox.vue postTweet method
console.log(tweet)
}
}
});
tweetPostBox.vue
<template>
<div class="post-box">
<div class="w-100 d-flex align-items-center">
<div class="profile-image rounded-circle"></div>
<input v-model="message" type="text" id="tweetText" placeholder="Whats happening?">
</div>
<div class="controls d-flex align-items-center w-100">
<button class="btn btn-primary ml-auto" #click="postTweet" id="postTweet">Tweet</button>
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
message: ''
}
},
methods: {
postTweet: async function(){
let response = await axios.post('/post', {
message: this.message
})
//How to get this response data to the main vue instance?
this.$emit('addTweet', response);
}
}
}
</script>
I'm trying to get the value into my app.js from the component file... but nothing is console logged. Where am I going wrong?
Update: Added HTML
<div class="container" id="app">
<tweet-postbox></tweet-postbox>
</div>
You should just need to change the template to:
<div class="container" id="app">
<tweet-postbox #add-tweet="addTweet"></tweet-postbox>
</div>
The #add-tweet part registers an event listener for the add-tweet event. I've used kebab case to avoid browser case-sensitivity problems. You'd need to emit the event with the same name, this.$emit('add-tweet', response). See the offical documentation to confirm that kebab case is the way to go.
The ="addTweet" parts assigns the method addTweet as the listener.
https://v2.vuejs.org/v2/guide/events.html#Method-Event-Handlers
Found this great answer on another post:
https://stackoverflow.com/a/47004242/2387934
Component 1:
<!-- language: lang-js -->
this.$root.$emit('eventing', data);
Component 2:
<!-- language: lang-js -->
mounted() {
this.$root.$on('eventing', data => {
console.log(data);
});
}
First of all, please fix your coding style, there's a lot of issues including indentation errors, try using eslint maybe.
Second, let's break this.$emit('addTweet') down a bit:
this is in that line refers to the instance of the Vue component, thus an instance of TweetPostBox.
When you call $emit with a addTweet, you're dispatching an event within the component.
Now that addTweet is dispatched, what's going to happen next? Vue is going to find all event handlers that handle addTweet and executes them.
Now in your case, you do not have any event handlers for this event. addTweet in your parent component is simply a local function in that component, it is not an event listener by any means.
To register an event listener, Vue provides # syntax, and you're already using that with #click, so just like you are doing #click="dosomething" (thus registering an event handler for onClick you need to use #add-tweet. (#addTweet also works but it is against coding style standards, Vue automatically handles the conversion for you)

How to use an image as a button in Vue.js?

I'm trying to make a login button as a single-file-component in Vue.js (it's a Rails app with a Vue.js front-end). If you click this button, it's supposed to take you to the an external provider's login page.
How can I use an image as a button? I'm guessing you use v-on:click for the actual redirect, but I'm stuck there.
Right now, this code below shows a hardcoded button that looks like img(src="../assets/img/login_button.png"). You can click on it, but that's obviously not what I want. I want to show the actual png image, not the path.
// LoginButton.vue
<template lang="pug">
#login-button
<button v-on:click="redirect_to_login">img(src="../assets/img/login_button.png")</button>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
#Component
export default class LoginButton extends Vue{
redirect_to_login():void{ // I haven't written this method yet
}
}
</script>
Is there any reason you can't just use normal HTML image inside your button? I haven't used pug before.
<button v-on:click="redirect_to_login"><img src="../assets/img/login_button.png" /></button
Though since you're using Vue and not an actual HTML form you might not even need a button you could just add the click binding to the image instead
<img src="../assets/img/login_button.png" v-on:click="redirect_to_login" />
I am not familiar with pug, so I don't know what the correct syntax you'll need is. But you can use the <router-link> tag to set the route. For example (using Vuetify)
<router-link to="/">
<v-img src="/path/to/img.gif"/>
</router-link>
Either you can use:
<a #click="Redirect">
<img src='IMAGE_SRC' />
</a>
or
<img #click="Redirect" src='IMAGE_SRC'/>
new Vue({
el: '#app',
methods:
{
Redirect()
{
window.location.href = "https://jsfiddle.net/";
//or
//this.$router.push('LINK_HERE'); // if ur using router
}
}
})
Demo LINK:
https://jsfiddle.net/snxohqa3/5/

Render one component several times in different html pages with different text

I'm new to react and I'm trying to render one component in different html files (because I'm working in an existing project), each of them with different text.
I'm thinking of something like this:
class ctaSection extends React.Component{
render(){
return(
<div className="cta-section">
<div className="md:w-9c">
<h5 className="uppercase">{this.props.h5}</h5>
<h3>{this.props.h3}</h3>
</div>
<div className="cta-button">
<a href="#">
<button className="w-full">{this.props.button}</button>
</a>
</div>
</div>
);
}
}
export default ctaSection;
Then, in my index.js, I'm rendering like this, passing the props:
let ctaPage1 = document.getElementById('cta-section-page-1');
let ctaPage2 = document.getElementById('cta-section-page-2');
ReactDOM.render(<CtaSection h3='my text for page 1' h5='my h5 for page 1' button='hello'/>, ctaPage1);
ReactDOM.render(<CtaSection h3='text for page 2' h5='something' button='click me'/>, ctaPage2);
I'm not sure if this is the best and simpler way to do this, because I'm calling ReactDOM.render twice for same component, and I got this error:
Uncaught Invariant Violation: Target container is not a DOM element.
This works fine if I render the component once, but not for multiple instances.
What is the best way to do it?
I've thought about this more, and I'm not experienced with adding React to existing websites, but here's what I'd suggest:
I would have 1 JS file per HTML page that imports CtaSection, each of those files would look like such:
// page1.js
import CtaSection from '../CtaSection'; // or wherever it is
let ctaPage = document.getElementById('cta-section-page');
ReactDOM.render(<CtaSection h3='my text for page 1' h5='my h5 for page 1' button='hello'/>, ctaPage);
You would just need to make sure each html page uses the corresponding JS file.
// page1.html
<body>
<div id="cta-section-page"></div>
<script src="page1.js"></script>
</body>
Repeat for each page.

React 16 Component does not render json data into component

I have a component called projectDetailPage where I am passing json variable to render it's value. I have a container component called ProjectCardContainer which has anchor tag and I am opening it to projectDetailPage I am attempting to render the json date and for that I am checking it with console.log(json);. When I click on ProjectCardContainer
<h6 className="link-hidden">
<a href={`/projectdetailpage/${props.projectID}`} >
{props.projectName}
</a>
</h6>
It opens projectDetailPage and I don't see any console.log. What is going wrong here? Also is there any correct approach for rendering json in to the component? Thanks.
Gist code Link
I forgot to Add the <Route path='/ProjectDetailPage/:projectID' component={ProjectDetailPage} /> in my root component. I Added it and solves my problem.

Categories

Resources