Pass data from Rails template to Vue Instance - ruby-on-rails

I've been trying to pass data from my Rails view to the Vue component as described here
Everything works much as expected, but I'm rather stumped as to how to access the data that I'm passing in via props. Not appearing in the Vue developer tools anywhere and I'm not able to find it by fiddling with/inside the Vue object.
Could someone point me in the right direction. I'm fairly green with Vue, so struggling to even know what to search for :/
show.html.erb
<%= javascript_pack_tag 'test_vue' %>
<%= stylesheet_pack_tag 'test_vue' %>
<%= content_tag :div, id: "test", data: {
message: "this wont!",
name: "nor will this!" }.to_json do %>
<% end %>
test.vue
<template>
<div id="app">
<p>{{test}}{{message}}{{name}}</p>
</div>
</template>
<script>
export default {
data: function () {
return {
test: 'This will display',
}
}
}
</script>
<style>
</style>
test_vue.js
import Vue from 'vue'
import Test from './test.vue'
document.addEventListener('DOMContentLoaded', () => {
const node = document.getElementById('test')
const props = JSON.parse(node.getAttribute('data'))
new Vue({
render: h => h(Test, { props })
}).$mount('#test');
})

Looks like all you need to do is declare the properties in your component:
<template>
<div id="app">
<p>{{test}}{{message}}{{name}}</p>
</div>
</template>
<script>
export default {
props: ["message","name"],
data: function () {
return {
test: 'This will display',
}
}
}
</script>
<style>
</style>
This would be the relevant documentation.
A child component needs to explicitly declare the props it expects to
receive using the props option

Related

svelte keep updating store var without clicking to update

My app automatically update $content value without me clicking on buttons. I know it is a simple question, but I can't find out why, I'm learning svelte.
App.svelte
<script>
import { content } from './store.js';
import Item from './Item.svelte';
$content = [{ id:0,obj: "Fell free to browse any category on top." }];
function addContent(value) {
$content = [{ id:0,obj: value}]
}
</script>
<li><button on:click={addContent("Home Page")}>Home</button></li>
<li><button on:click={addContent("Products Page")}>Products</button></li>
<div class="Content">
<p>Fell free to browse any category on top.</p>
{#each $content as item}
<p><svelte:component this={Item} objAttributes={item} /></p>
{/each}
</div>
store.js
import { writable } from 'svelte/store';
export let content = writable({});
Item.svelte
<script>
import { fade } from 'svelte/transition';
export let objAttributes = {};
</script>
<p transition:fade>
{objAttributes.obj}
{#if objAttributes.otherattrib}<em>{objAttributes.otherattrib}</em>{/if}
</p>
This is because your on:click events are defined wrongly.
The on:click takes as argument a function like this
<button on:click={functionGoesHere}>
or, if you want it inlined
<button on:click={() => { }>
What happens in your case is that you directly call a function and the result of this function will then be called when the button is clicked. You can see that in this example:
<script>
function createFn() {
return () => console.log('logging this')
}
</script>
<button on:click={createFn}>Click here</button>
in this example the function () => console.log('logging this') will be attached the button.
So to come back to your code, this is easily fixed by making it a function instead of a function call:
<li><button on:click={() => addContent("Home Page")}>Home</button></li>

Images not loading on page change using Link in NextJS

This is hard to explain without uploading my full project likely, but here goes. I think I've narrowed it down to some combination of getInitialProps() and getStaticProps(). When I use next/link to change pages images are not being loaded. If I browse directly to the page images will load fine. Project is fairly simple with only 2 pages, index.js and [slug].js. Here's both:
index.js
import React from 'react';
import Layout from '../components/layout';
import Seo from '../components/seo';
import Hero from '../components/hero';
import Forcast from '../components/forcast';
import { fetchAPI } from '../lib/api';
import ReactMarkdown from 'react-markdown';
const Home = ({ pages, homepage }) => {
return (
<Layout pages={pages}>
<Seo seo={homepage.seo} />
<Hero hero={homepage.hero} />
<Forcast />
<main className='main-content'>
<div className='fullwidth-block'>
<div className='container'>
<div className='post single'>
<div className='entry-content'>
<ReactMarkdown
source={homepage.Content}
escapeHtml={false}
transformImageUri={uri =>
uri.startsWith('http') ? uri : `${process.env.REACT_APP_IMAGE_BASE_URL}/${uri}`
}
/>
</div>
</div>
</div>
</div>
</main>
</Layout>
);
};
export async function getStaticProps() {
// Run API calls in parallel
const [pages, homepage] = await Promise.all([
fetchAPI('/pages'),
fetchAPI('/homepage'),
]);
return {
props: { pages, homepage },
revalidate: 1,
};
}
export default Home;
[slug].js
import ReactMarkdown from 'react-markdown';
import Layout from '../components/layout';
import Seo from '../components/seo';
import { fetchAPI } from '../lib/api';
const Page = ({ page, pages }) => {
const seo = {
metaTitle: page.Title,
metaDescription: page.seo.metaDescription,
shareImage: page.seo.shareImage,
}
return (
<Layout pages={pages}>
<Seo seo={page.seo} />
<main className='main-content'>
<div className='container'>
<div className='breadcrumb'>
</div>
</div>
<div className='fullwidth-block'>
<div className='container'>
<div className='row'>
<div className='content col-md-8'>
<div className='post single'>
<h2 className='entry-title'>{page.Title}</h2>
<ReactMarkdown
source={page.Content}
escapeHtml={false}
transformImageUri={uri =>
uri.startsWith('http') ? uri : `${process.env.REACT_APP_IMAGE_BASE_URL}${uri}`
}
/>
</div>
</div>
</div>
</div>
</div>
</main>
</Layout>
);
};
export async function getStaticPaths() {
const pages = await fetchAPI('/pages');
return {
paths: pages.map((page) => ({
params: {
slug: page.slug,
},
})),
fallback: false,
};
}
export async function getStaticProps({ params }) {
const pages = await fetchAPI(
`/pages?slug=${params.slug}`
);
return {
props: { page: pages[0], pages },
revalidate: 1,
};
}
export default Page;
This might also be a Strapi issue though I'm not sure.
The issue happens because the REACT_APP_IMAGE_BASE_URL is not exposed to the browser, and only available on the server.
To have it exposed to the browser you'll need to add the NEXT_PUBLIC_ prefix to it.
# .env.development
NEXT_PUBLIC_REACT_APP_IMAGE_BASE_URL=http://localhost:1337
Then in your code reference it using process.env.NEXT_PUBLIC_REACT_APP_IMAGE_BASE_URL.

Google charts does not always load in first attempt

I ask advice. Google chart is not always loaded on the first attempt ... how to solve this problem?
demo
view:
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Time', 'TempC'],
<% #data.css("hourly").each do |hrly| %>
['<%= hrly.css("time").text %>',<%= hrly.css("tempC").text %>],
<% end %>
]);
var options = {
title: 'Temperature forecast'
};
var chart = new google.visualization.AreaChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
</script>
<div id="chart_div" style="width: 100%; height: auto;"></div>
controller
class WwoController < ApplicationController
def weather
require 'nokogiri'
url = "https://api.worldweatheronline.com/premium/v1/weather.ashx?q=59.94%2C30.31&num_of_days=4&key=***********************************"
#data = Nokogiri::XML(open(url))
end
end
If you use turbolinks, try to disable it in that page, because I have similar problems with google maps apis
to disable turbolinks you can add this to your application.html.erb
<body <%= yield(:body_attributes) %>>
then in your view.html.erb add this in first line
<%= content_for(:body_attributes, 'data-no-turbolink') %>
you can also disable turbolink with link_to
<%= link_to 'link_name', your_link_path, 'data-no-turbolink' => true %>
if you use rails/turbolinks 5
change data-no-turbolink into data-turbolinks and switch the boolean value
also try to put your javascript in the bottom. to make it loaded after the html dom.

My request for a second view it doesn't show anything

I'm using ruby on rails as framework and vue.js to display de data and for the request to the API I'm using axios.
first I create project with:
rails new myapp --webpack=vue
that created one folder in rails:
app/javascript
└── packs
├── app.vue
└── hello_vue.js
app.vue:
<template>
<div id="app">
<ul v-for="result in results">
<li>{{result.name}}</li>
</ul>
<!-- <p>{{ results.name}}</p> -->
</div>
</template>
<script>
export default {
data: {
results: []
},
mounted(){
axios.get("xxxxx")
.then(response => {
this.results = response.data
})
}
}
</script>
hello_vue.js:
import Vue from 'vue'
import App from './app.vue'
document.addEventListener('DOMContentLoaded', () => {
document.body.appendChild(document.createElement('hello'))
const app = new Vue(App).$mount('hello')
console.log(app)
})
that allow me to insert the information in the views like:
<%= javascript_pack_tag 'hello_vue' %>
and works it show the information.
But when I try to make a new folder with new files like this :
app/javascript
└── datos
├── app2.vue
└── hello2_vue.js
app2:
<template>
<div id="app2">
<ul v-for="result in results">
<li>{{result.name}}</li>
</ul>
</div>
</template>
<script>
export default {
data: {
results: []
},
mounted(){
axios.get("xxxxxxxxxxxx")
.then(response => {
this.results = response.data
})
}
}
</script>
hello2:
import Vue from 'vue'
import App2 from './app2.vue'
document.addEventListener('DOMContentLoaded', () => {
document.body.appendChild(document.createElement('hello2'))
const app2 = new Vue(App2).$mount('hello2')
console.log(app2)
})
and them load the files:
<%= javascript_datos_tag 'hello2_vue' %>
it show this error:
undefined method `javascript_datos_tag' for #<#<Class:0x0055a86f9b0218>:0x007fd3cf6d9958>
Did you mean? javascript_cdata_section
javascript_tag
javascript_pack_tag
Sorry for that guy I just check my server foreman and apparently it needs to be re-start every time I add new views ans requests, in the foreman server like.
$foreman start

Rails + Angular : Issue with directive

I have Rails 4.2.4 and Angular 1.4.8.
I am trying define a directive:
index.html:
<div ng-app='myApp' ng-controller='myController'>
<foo bar='bar'></foo>
</div>
app.js:
angular.module('myApp', ['templates']);
angular.module('myApp', ['templates']).directive('foo', function(){
return {
restrict: 'AE',
scope: {
bar: '='
},
templateUrl: 'bar.html'
}
});
angular.module('myApp').controller('myController', function($scope, $http){
$scope.bar = "XMan";
});
bar.html:
<h1> Hi {{ bar }}! </h1>
<ng-include src="'{{bar}}.html'"
XMan.html:
<p>Hello I'm XMan</p>
Here I am expecting my foo directive to render
<h1> Hi X Man! </h1>
<p> Hello I'm XMan </p>
but I am getting
<h1> Hi {{ bar }}! </h1>
<!-- ngInclude: undefined -->
What is wrong with my approach. Please guide me; I am very new to Angular.js.
I got a solution. We cannot bind ng-include src with scope variable.
Instead I used function call to get the source then it works!
That is I changed
<ng-include src="'{{bar}}.html'"
to
<ng-include src="barUrl()"
and added a controller scope function:
$scope.barUrl = function(){
return $scope.bar + '.html'
}

Resources