Rails 7 toastr using importmaps - ruby-on-rails

Im trying to use toastr to display a message. Im using rails 7 but Im unsure if i have it imported and implemented correctly
import { Controller } from "#hotwired/stimulus";
import { initializeApp } from 'firebase';
import { getMessaging, getToken, onMessage } from "firebase-messaging";
// import { onBackgroundMessage } from "firebase-messaging-sw";
import * as toastr from 'toastr';
onMessage(messaging, (payload) => {
alert(`${ payload.notification.title }\n ${ payload.notification.body }`);
toastr['success']("Message will come here", "Title");
});
That last line is where nothing happens. the alert shows up as expected
pin "toastr", to: "https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"
That is my pin statement in importmap.rb
<head>
<title>NitroCabs</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/firebase-messaging-sw.js');
});
}
</script>
<%= favicon_link_tag asset_path('firebase-logo.png') %>
That is my head in application.html.erb

Related

How to include an url in application.html.erb in rails 6?

I am trying to add Google Map in my rails app. I followed the guidance link: https://medium.com/#pjbelo/using-google-maps-api-v3-with-rails-5-2-b066a4b2cf14
(But I use rails 6)
and I have my code:
application.html.erb:
<head>
<title>GmapTry</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'https://maps.googleapis.com/maps/api/js?key=AIzaSyA7ClwnGU9QTuNhY3DuVqM5K5YbWA7zJsI' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= yield(:head_tags) %>
</head>
<body>
<%= yield %>
</body>
<% provide :head_tags do %>
<meta name='turbolinks-visit-control' content='reload'>
<script>
document.addEventListener("DOMContentLoaded", function(){
initMap(<%=#place.latitude%>, <%=#place.longitude%>)
});
</script>
<% end %>
...
...
<p>
<div id="map"></div>
</p>
places.js
function initMap(lat, lng) {
var myCoords = new google.maps.LatLng(lat, lng);
var mapOptions = {
center: myCoords,
zoom: 14
};
var map = new google.maps.Map(document.getElementById('map'), mapOptions);
}
application.js
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
require("gmaps/google")
require("packs/places")
Actually when I followed the first step to show the static map, it works well like:
but when I go to next step with js, nothing shows up now. Anybody knows why?
In rails 6, is there anything wrong to write %= javascript_include_tag 'https://maps.googleapis.com/maps/api/js?key=AIzaSyA7ClwnGU9QTuNhY3DuVqM5K5YbWA7zJsI' %in application.html.erb?
Every maps tutorial I have seen leads to a dead end of inline script tags and globals when its actually really pretty easy to do the job "the right way".
Just use an element with data attributes to pass information from the view to your JavaScript:
<%= content_tag :div,
"",
class: 'google-maps-widget', # call it whatever you want
data: {
lat: #place.latitude,
lng: #place.longitude
}
%>
You can ideally DRY this code into a helper method. Then just setup an event handler that loads the map on the initial page load or when turbolinks refreshes the page.
document.addEventListener("turbolinks:load", function(){
// find the maps on the page
let maps = document.querySelectorAll(".google-maps-widget");
// loop through the maps
maps.forEach(function(element){
let data = element.dataset;
if (!data.initialized) {
let map = new google.maps.Map(element, {
// you can just use a object literal instead
center: { lat: data.lat, lng: data.lng },
// lets you override the inital zoom
zoom: data.zoom || 14
});
// This keeps the element from being re-initialized
// if turbolinks persists it
element.dataset.initialized = "true";
}
});
});
If you want to add a bunch of markers to the map you can either just add a bunch of elements inside the <div class="google-maps-widget"... element:
<div class="google-maps-widget" ... >
<div class="marker hidden" data-lng="1" data-lng="2">My Favorite spot</div>
...
<end>
You would then parse these out when initializing the map. Or you add a data attribute to the map element with a URI where you can fetch the markers via AJAX.

Google Map Javascript Only loads after refresh

Using Google Map API, I have embedded Google Map (Javascript) in my page. However, the map will only load after I refresh the page once.
I looked up on many past threads, to which many mentioned the caused related turbolinks.
I tried many of those but still it didn't work.
Application.html.erb
<%= yield %>
<%= javascript_include_tag "https://maps.googleapis.com/maps/api/js?libraries=places&key=#{ENV['GOOGLE_API_BROWSER_KEY']}" %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application' %>
<%= javascript_pack_tag "map" %>
Show.html.erb
<div id="map"
style="width: 100%;
height: 300px;"
data-markers="<%= #markers.to_json %>"
></div>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['GOOGLE_API_BROWSER_KEY'] %>&callback=initMap"
type="text/javascript"></script>
javascript/packs/map.js
import GMaps from 'gmaps/gmaps.js';
const mapElement = document.getElementById('map');
if (mapElement) {
const map = new GMaps({ el: '#map', lat: 0, lng: 0 });
const markers = JSON.parse(mapElement.dataset.markers);
map.addMarkers(markers);
if (markers.length === 0) {
map.setZoom(2);
} else if (markers.length === 1) {
map.setCenter(markers[0].lat, markers[0].lng);
map.setZoom(14);
} else {
map.fitLatLngBounds(markers);
}
}
Please let me know if you have any additional question or if you need anymore info.
Appreciate all your helps!

Rails geocoding/Mapbox GL JS "missing CSS declarations for Mapbox GL JS" "_typeof is not defined"

I want to display my MapBox map into may <div id="map">... but I'm getting two errors: >This page appears to be missing CSS declarations for Mapbox GL JS... and >_ReferenceError: _typeof is not defined
I read a lot of issues about it on the web but still doesn't work :/
views/layouts/applications.html.erb
<html>
<head>
<title>MarryApp</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<!-- <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.2/mapbox-gl.css" rel="stylesheet" /> -->
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= stylesheet_pack_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
</head>
<body>
<%= render 'shared/navbar' %>
<%= render 'shared/flashes' %>
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 p-0">
<%= yield %>
</div>
</div>
</div>
<%= javascript_pack_tag 'application' %>
</body>
</html>
app/javascript/packs/application.js
import 'mapbox-gl/dist/mapbox-gl.css';
import { initMapbox } from '../plugins/mapbox';
initMapbox();
app/javascript/plugins/mapbox.js
import mapboxgl from 'mapbox-gl';
const initMapbox = () => {
const mapElement = document.getElementById('map');
if (mapElement) { // only build a map if there's a div#map to inject into
mapboxgl.accessToken = mapElement.dataset.mapboxApiKey;
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v10'
});
}
console.log(mapElement.dataset.mapboxApiKey)
};
export { initMapbox };

Why am i getting an error Uncaught TypeError: Cannot read property 'insertAdjacentHTML' of null at renderHTML

How do I get my information to render and not display an error? I was following a video and I'm also having a few other console errors that may or may not be affecting it also.
var bitprice = document.getElementById('bitprice');
$( document ).ready(function() {
var bitcoin = new XMLHttpRequest();
bitcoin.open('GET', "https://api.coindesk.com/v1/bpi/currentprice.json");
bitcoin.onload = function() {
// console.log(bitcoin.responseText);
var bitdata = JSON.parse(bitcoin.responseText);
// console.log(bitdata.bpi.USD.rate);
renderHTML(bitdata.bpi.USD.rate);
};
bitcoin.send();
});
function renderHTML(data) {
bitprice.insertAdjacentHTML('beforeend',"test")
}
<!DOCTYPE html>
<html>
<head>
<title>Bitview</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %> (Inside the yield is as follows <div id="bitprice"></div>)
<script type="text/javascript" src="app/assets/javascripts/js.js"></script>
</body>
</html>
why is var bitprice outside of the function that is using it? Try defining it inside the function and it should work.
There's a thing to learn about called "scope". The way javascript works - something outside the function might not be visible inside the function because of the way scope works. It's worth googling about for a good article or two.

[Rails][Vue] Empty array returned when fetching the children nested within a parent component. Any idea why is this happening?

I'm using Rails 5.1 + Webpack running Vue 2. I'm fairly new to Vue, not so new to Rails.
I'm building a navbar component starting from the Bulma navbar. My objective is to be able to dynamically create links in the navbar by simply adding a navlink element nested within.
In my application.html.erb I have already created this structure (navlink nested inside navbar).
In hello_vue.js I'm initializing the Vue components and assigning them to a root element (one for the navbar and one for the rest of the content).
In navbar.vue, I'd like to iterate through all the and create a menu item accordingly. In order to do so, I added an empty navlinks data to navbar that I want to populate once it gets mounted() by fetching all its children (the nested navlink tags).
This is however not working, whenever I reference this.$children I get an empty array. Any idea why is this happening?
This is all the code.
application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>RailsVue</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'hello_vue' %>
</head>
<body>
<div id="navbar-container">
<navbar>
<navlink href="http://google.com">
Link 1
</navlink>
<navlink href="http://facebook.com">
Link 2
</navlink>
</navbar>
</div>
<%= yield %>
<%= javascript_pack_tag 'hello_vue' %>
</body>
</html>
hello_vue.js
import Vue from 'vue/dist/vue.esm'
import App from './app.vue'
import Navlink from './components/navlink.vue'
import Navbar from './components/navbar.vue'
const navbar = new Vue({
el: "#navbar-container",
components: { Navbar, Navlink }
})
const app = new Vue({
el: '#hello',
data: {
message: "Can you say hello?"
},
components: { App }
})
navbar.vue
<template>
<div>
<nav class="navbar is-transparent">
<div class="navbar-brand">
<a class="navbar-item" href="http://bulma.io">
<img src="http://bulma.io/images/bulma-logo.png" alt="Bulma: a modern CSS framework based on Flexbox" width="112" height="28">
</a>
<div class="navbar-burger burger" data-target="navMenuTransparentExample">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div id="navMenuTransparentExample" class="navbar-menu">
<div class="navbar-start">
<a v-for="navlink in navlinks" class="navbar-item" :href="navlink.href">
<slot></slot>
</a>
</div>
</div>
</nav>
</div>
</template>
<script>
import Navlink from './navlink.vue'
export default {
name: "Navbar",
data: function () {
return {
navlinks: []
}
},
created: function(){
// let children = this.$children;
console.log(this.$children);
// this.navlinks = this.$children;
// this.navlinks = this.$children;
}
}
</script>
navlink.vue
<template>
<div class="navlink">
<slot></slot>
</div>
</template>
<script>
export default {
name: "Navlink"
}
</script>
Instead of created hook, use mounted hook, you can able to get this.$children
mounted : function(){
// let children = this.$children;
console.log(this.$children);
// this.navlinks = this.$children;
// this.navlinks = this.$children;
}
You can modify components to achieve your requirement as follows
application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>RailsVue</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'hello_vue' %>
</head>
<body>
<div id="navbar-container">
<navbar>
<navlink>
<a class="navbar-item" href="http://google.com">
Link 1
</a>
</navlink>
<navlink>
<a class="navbar-item" href="http://facebook.com">
Link 2
</a>
</navlink>
</navbar>
</div>
<%= yield %>
<%= javascript_pack_tag 'hello_vue' %>
</body>
</html>
hello_vue.js
import Vue from 'vue/dist/vue.esm'
import App from './app.vue'
import Navlink from './components/navlink.vue'
import Navbar from './components/navbar.vue'
const navbar = new Vue({
el: "#navbar-container",
components: { Navbar, Navlink }
})
navbar.vue
<template>
<div>
<nav class="navbar is-transparent">
<div class="navbar-brand">
<a class="navbar-item" href="http://bulma.io">
<img src="http://bulma.io/images/bulma-logo.png" alt="Bulma: a modern CSS framework based on Flexbox"
width="112" height="28">
</a>
<div class="navbar-burger burger" data-target="navMenuTransparentExample">
<span></span>
<span></span>
<span></span>
</div>
</div>
<slot></slot>
</nav>
</div>
</template>
<script>
// import Navlink from './navlink.vue'
export default {
name: 'Navbar',
data: function () {
return {
navlinks: []
}
},
mounted: function () {
// let children = this.$children;
// console.log(this)
console.log(this.$children)
// console.log(this.$root.$children[0])
// this.navlinks = this.$children
// this.navlinks = this.$children;
}
}
</script>
navlink.vue
<template>
<div class="navlink">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'Navlink'
}
</script>

Resources