I'm using the react-rails gem, and I'm having trouble figuring out how to load images from the asset pipeline.
I handle this currently by using the .js.jsx.erb extension, but as far as I know this is unconventional. (am I correct?)
Sometimes I just use an empty div and and set the div's background-image property as the image I intend to use.
What is the best way to go about loading images to react components when using react-rails?
There are three ways to import image...
1) If you are direct using jsx.erb or js.erb file...
var image_path = "<%= asset_path(my_image.png) %>"
OR
render: function() {
return (
<img src={"<%= asset_url('path/to/image.png') %>"} />
)
}
2) Passing as props Through .erb file to .js.erb or .jsx.erb file
in your .erb file
render_component('Component', img_src: image_url('the_path'))
in your .js.erb or .jsx.erb file
render: function() {
return (
<img src={this.props.img_src} />
)
}
3) Recommended: Use .js and .jsx file and render it using view file .html.erb
In view file example.html.erb
<%= react_component("Example", props: {}, prerender: false) %>
In .jsx file Example.jsx
import React, { Component } from "react";
import Image from "<IMAGE_PATH>/image.png";
export default class Example extends Component {
constructor(props, _railsContext) {
super(props);
}
render(){
return(
<div>
<img src={Image} alt="example" />
</div>
)
}
}
You need to register Example component. In your app > javascript > packs > application.js
import ReactOnRails from "react-on-rails";
import Exmaple from "<COMPONENT_PATH>/Exmaple";
ReactOnRails.register({
Exmaple
});
Source: github
Related
I'm trying to make a shopify app and I want to use ruby on rails with polaris and reactJS. When I try to use the Page component taken from shopify's website, nothing ever gets rendered to the screen. Here's an example of what I'm talking about.
This is my index.jsx file:
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import {AppProvider, Page, Card} from '#shopify/polaris'
import '#shopify/polaris/styles.css'
document.addEventListener('DOMContentLoaded', () => {
ReactDOM.render(
<Page title="Jar Witock-Lid"> //Here is where I use the Page tag
<p>Other content</p>
</Page>,
document.body.appendChild(document.createElement('div')),
)
})
Everything else is working fine because when I change the Page tag to be a div like this:
document.addEventListener('DOMContentLoaded', () => {
ReactDOM.render(
<div>
<div>{"One"}</div>
<div>{"Two"}</div>
<div>{"Three"}</div>
</div>,
document.body.appendChild(document.createElement('div')),
)
})
It would render ("One" "Two" "Three") to the page. When I run my rails server and refresh the screen, no errors or warning are displayed. I downloaded polaris by running this command: yarn add #shopify/polaris.
Any help is greatly appreciated. I tried looking all over the web but I couldn't put the pieces together. Thanks in advance!
I found the solution. The only thing I was missing was wrapping it all in an AppProvider tag like this:
document.addEventListener('DOMContentLoaded', () => {
ReactDOM.render(
<AppProvider>
<Page title="Jar Witock-Lid">
<p>content</p>
</Page>
</AppProvider>,
document.body.appendChild(document.createElement('div')),
)
})
I'm kinda new to Vue.js but today I am trying to setup some sort of map to show data. I ended up picking Highmaps since it seemd like the best alternative of the bunch and also because I already used it (Highcharts) for other projects.
Now the problem arises because I am developing a component driven webapp but I want to import maps from Highmaps. Since they just use CDN paths I don't really know how to implement them by using the import statement. Below is some code to make you understand better.
--- main.js ---
import Vue from 'vue'
import App from './App'
import MapComponent from './components/MapComponent.vue'
import Highcharts from 'highcharts';
import HighMaps from '../node_modules/highcharts/highmaps.js'
import VueHighcharts from 'vue-highcharts'
import loadMap from 'highcharts/modules/map';
loadMap(Highcharts);
Vue.use(VueHighcharts, { Highcharts });
Vue.use(HighMaps);
Vue.component('app-map', MapComponent)
new Vue({
el: '#app',
router: router,
components: { App },
template: '<App/>'
})
------------------------
--- MapComponent.vue ---
<template>
<div>
<highmaps :options="chartOptions"></highmaps>
</div>
</template>
<script>
import Element from 'element-ui';
import axios from 'axios';
import HighCharts from 'vue-highcharts';
export default {
data () {
return {
chartOptions: {
chart: {
map: 'countries/it/it-all'
},
...
}
},
}
</script>
This is what you can see from the browser, the errors appear when I try to press the + / - or when I scroll inside the map's borders
As you can see inside the script tag I already imported some libraries but I can't undestand how to import Highmaps too.
I can see in the image you have an error:
Uncaught ReferenceError, HighCharts is not defined at ...
This is because, whenever you import a library for Vue, you should provide it as a component.
So, you have to add this:
import HighCharts from 'vue-highcharts';
export default {
//...
components: { HighCharts },
//...
}
The problem here it's that the CDN imports VueHighcharts, you can register it globally as
Vue.use(VueHighcharts, { Highcharts: Highcharts })
and then use it everywhere
<highmaps :options="options"></highmaps>
Take a look at the examples on the bottom of the Lib Readme
Also, it's better to install it via npm to have a better modular structure to work with webpack (or whatever you use)
Right now I have found a way (probably cheesy) to force the map data into the map itself by copy pasting the object inside a variable and then referencing it into the chart.map
I understand that this is probably very bad since Vue needs to go and compile all of that object right inside the component but I hope it is a temporary solution.
<template>
<div>
<highmaps :options="chartOptions"></highmaps>
</div>
</template>
<script>
import Element from 'element-ui';
import axios from 'axios';
import HighCharts from 'vue-highcharts';
export default {
data () {
var country= {"title":"Italy","version":"1.1.2","type":"FeatureCollection","copyright":"Copyright...}
return {
chartOptions: {
chart: {
map: country
},
...
}
</script>
You can find the map data at this url (choose the GeoJSON option)
EDIT
I have finally found a good way of doing this by just saving the raw json data of the map into a local .json file and importing it as follows:
<template>
<div>
<highmaps :options="chartOptions"></highmaps>
</div>
</template>
<script>
import HighCharts from 'vue-highcharts';
import json from '../map.json'
export default {
data () {
return {
chartOptions: {
chart: {
map: json,
},
...
}
</script>
I'm trying to use VueStrap in a VueJS project, it looks like webpacker is loading it fine, I can see this in the terminal output, however, when I try use a component from vue-strap I get this error:
[Vue warn]: Property or method "input" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
I tried including the VueStrap as a component in the Vue instance but couldn't get it to work. How do I include the VueStrap into as a component correctly?
Thanks!
This is my application.js:
import Vue from 'vue/dist/vue.js'
import App from '../components/app.vue'
import VueStrap from 'vue-strap'
document.addEventListener('DOMContentLoaded', () => {
document.body.appendChild(document.createElement('app'))
const app = new Vue({
el: 'app',
template: '<App/>',
components: { App }
})
console.log('app')
})
This is my app.vue file
<template>
<div id='app'>
<p> {{ message }} </p>
<bs-input :value.sync="input" label="Username" help="Only allows lowercase letters and numbers."
error="Insert username" placeholder="Username can't start with a number." pattern="^[a-z][a-z0-9]+$"
:mask="mask" minlength="5" readonly required icon>
</bs-input>
</div>
</template>
<script>
export default {
data: function () {
return {
message: "Hello World"
}
}
}
</script>
<style scoped>
p {
font-size: 2em;
text-align: left;
}
</style>
Please see the documentation on complication scope, notably:
Everything in the parent template is compiled in parent scope; everything in the child template is compiled in child scope.
Your template includes input and mask properties but your data function does not set those up. They need to be set up and reactive so if they change, Vue can pass them down to the child component (which it looks like your bs-input component exposes an input and mask properties).
I just added the react-rails gem to my project and tried to add a react component to my index.html.erb file. I used the react component generator to make a simple message/text element, but it does not show up on my view after I deploy to Heroku, but it seems to render when I inspect the page. I have no idea why this isn't working.
Please look at the images I have attached. It looks like the javascript doesn't get compiled??
Body inspection part 2
index.html.erb code
<h2>Dashboard</h2>
<%= react_component('Message', text: 'hello') %>
<h3>Products TEST REACT </h3>
Message.jsx code
var React = require("react")
class Message extends React.Component {
render () {
return (
<div>
<div>Text: {this.props.text}</div>
</div>
);
}
}
Message.propTypes = {
text: React.PropTypes.string
};
module.exports = Message
HTML body inspection
I reverted to the git commit before installing react-rails and used the shakacode react-on-rails gem instead and got it to work
The registration was working fine with the default HelloWorld app, but once I deleted the folder and created my own, it stopped working.
I made a new folder under app/bundles called posts with a startup folder.
In the startup folder, I'm registering the components like so:
import ReactOnRails from 'react-on-rails';
import PostContainer from '../containers/PostContainer';
ReactOnRails.register({
PostContainer
});
The PostContainer.jsx file is in the containers folder and it looks like this:
import React, { PropTypes, Component } from 'react';
export default class PostsContainer extends React.Component {
render() {
return (
<div>
<Header />
<PostList posts={this.props.posts} />
</div>
)
}
}
My webpack.config.js file looks like this:
entry: [
'es5-shim/es5-shim',
'es5-shim/es5-sham',
'babel-polyfill',
'./app/bundles/HelloWorld/startup/registration',
],
I tried changing the HelloWorld to posts or Posts, but it did not work.
Am I supposed to have a file called webpack.configure.build.js? Or is the webpack.config.js the file I need to edit?
Any help would be appreciated!
Did you add the component to the erb view file with the associated props passed in? You would need to add the props within your Posts controller or whichever controller is rendering your Posts view. I'm pretty sure you would then need to add a line in your webpack config:
config: {
'webpack-bundle': [
'...',
'./app/bundles/Posts/startup/registration'
]
}
Then in your view:
<%= react_component("PostsContainer", props: #posts_props, prerender: false) %>
Also make sure in your layout file you have:
<%= javascript_pack_tag 'webpack-bundle' %>
Note: PropTypes should be imported from the prop-types package now. The react team plucked that package out of the react core as of recent.