How to add link to marker using gmaps4rails gem - ruby-on-rails

I would like to add a marker with link in marker, so, when i click that marker, i will redirect to another page
Is anybody know to do it?
Thanks
I already added my code like this :
In controller:
#json = #businesses.results.to_gmaps4rails do |object|
"\"link\": \"#{root_url}\""
end
In view :
<%= gmaps4rails(#json) %>
<% content_for :scripts do %>
<script type="text/javascript">
function redirect_to(url) {
window.location = url;
};
Gmaps4Rails.callback = function() {
function say_yo(arg) { return function(){alert('yo '+ arg + '!' );};};
for (var i = 0; i < Gmaps4Rails.markers.length; ++i) {
google.maps.event.addListener(Gmaps4Rails.markers[i].google_object, 'click', redirect_to(Gmaps4Rails.markers[i].link));
}
}
</script>
<% end %>
Is it any wrong? because there just an info window that show after i clicked the marker(Not redirect to any page)

First include the link inside the json:
Model.all.to_gmaps4rails do |object|
"\"link\": \"your link as string\""
end
Then add the extra listeners in your view (beware to include this AFTER your call to the gmaps method):
<%= gmaps(whatever you need here) %>
<% content_for :scripts do %>
<script type="text/javascript">
function redirect_to(url) {
window.location = url;
};
Gmaps4Rails.callback = function() {
function say_yo(arg) { return function(){alert('yo '+ arg + '!' );};};
for (var i = 0; i < Gmaps4Rails.markers.length; ++i) {
google.maps.event.addListener(Gmaps4Rails.markers[i].google_object, 'click', redirect_to(Gmaps4Rails.markers[i].link));
}
}
</script>
<% end %>

Related

Typing indicator with action cable in rails- 7

I am unable to add typing indicator in my rails app with action cable I have created app in rails 7 and I user trubo stream tag and broadcast in it so I did't used channel for live chat , I tried to find tutorial and video but there is not any
I want to add typing indicator so I writtern js for the same on input it will called and it will go to controller
On input I am calling controller "rtm"
room controller
def rtm
#typing = "hhhhhhhhhhhhhhhhhhh"
# ActionCable.server.broadcast "typing_channel",{ message: "helloo"}
# #typings.broadcast_append_to "typing"
Turbo::StreamsChannel.broadcast_append_to "typing", target: 'typing', partial: 'rooms/typing', locals: { message: "#typing" }
end
here I have issue how can I broadcast the typing message to my room page
Room.rb
class Room < ApplicationRecord
scope :public_rooms, -> { where(is_private: false) }
has_many :messages
after_create_commit {broadcast_append_to "rooms"}
end
message.rb
class Message < ApplicationRecord
belongs_to :user
belongs_to :room
after_create_commit { broadcast_append_to self.room }
end
rooms/index
<script>
$(document).ready(function(){
var tmo = null;
$("#msg").on("input", function(){
$.ajax({
type: 'GET',
url: '/rooms/rtm',
data: {data: ''}
});
document.getElementById("typing").innerHTML = "Typing...";
if (tmo) {
clearTimeout(tmo);
}
tmo = setTimeout(function () {
$.ajax({
type: 'GET',
url: '/rooms/rmm',
data: {data: ''}
});
document.getElementById("typing").innerHTML = "";
}, 1000);
});
});
</script>
<div class="container">
<h5> Hi <%= current_user&.firstname %> </h5>
<%= debug(params) if Rails.env.development? %>
<br> <h4> Rooms </h4>
<%= render partial: 'layouts/new_room_form' %>
<%= turbo_stream_from "rooms" %>
<div id="rooms">
<%= render #rooms %>
</div>
</div>
<% if #single_room.present? %>
<%= link_to #single_room.name,#single_room, class: "btn btn-primary" %>
<%= turbo_stream_from #single_room %>
<div id="messages">
<%= render #messages %>
</div>
<%= render partial: 'layouts/new_message_form' %>
<%= #typing %>
<%= turbo_stream_from #typing %>
<div id="typing">
</div>
<%= render partial: 'rooms/typing' %>
<span id="typing"></span><br>
<% end %>
To get the typing indicator you need to use action cable and create a channel for it. You can use turbo stream to render the typing indicator. Example:
app/channels/typing_channel.rb
class TypingChannel < ApplicationCable::Channel
def subscribed
stream_from "typing_channel"
end
end
app/javascript/channels/typing_channel.js
import consumer from "./consumer"
consumer.subscriptions.create("TypingChannel", {
connected() {
// Called when the subscription is ready for use on the server
},
disconnected() {
// Called when the subscription has been terminated by the server
},
received(data) {
// Called when there's incoming data on the websocket for this channel
}
});
app/views/rooms/index.html.erb
<div id="typing">
<%= turbo_stream_from "typing_channel" %>
</div>
app/views/rooms/_typing.html.erb
<p><%= message %></p>
app/controllers/rooms_controller.rb
class RoomsController < ApplicationController
def rtm
ActionCable.server.broadcast "typing_channel", { message: "helloo" }
end
end
app/javascript/controllers/rooms_controller.js
import { Controller } from "stimulus"
import consumer from "../channels/consumer"
export default class extends Controller {
static targets = [ "input" ]
connect() {
this.subscription = consumer.subscriptions.create("TypingChannel", {
received: (data) => {
this.renderTyping(data)
}
})
}
renderTyping(data) {
const typing = document.getElementById("typing")
typing.innerHTML = data.message
}
disconnect() {
this.subscription.unsubscribe()
}
}
Is not possible to use turbo stream with action cable. You need to use action cable to get the typing indicator. You can use turbo stream to render the typing indicator.
typing_channel.js
import consumer from "channels/consumer"
consumer.subscriptions.create("TypingChannel", {
connected() {
console.log("connected")
// Called when the subscription is ready for use on the server
},
disconnected() {
// Called when the subscription has been terminated by the server
},
received(data) {
console.log(data)
const box = document.getElementById('typing');
if (box.textContent.includes(data.body)) {
} else {
$('#typing').append('<p>'+ data.body + data.message +'</p>');
}
}
});
I am using below js for indicator
<script>
$(document).ready(function(){
var tmo = null;
$("#chat").on("input", function(){
$.ajax({
type: 'GET',
url: '/rooms/rtm',
});
if (tmo) {
clearTimeout(tmo);
}
tmo = setTimeout(function () {
$.ajax({
type: 'GET',
url: '/rooms/rmm',
});
}, 1000);
});
});
</script>
in controller
ActionCable.server.broadcast "typing_channel", {message: 'Typing', body: "#{current_user.email}"}

Gmaps4rails: map does not show through ajax with erb data feeding but does when hard coded

I would like to use the gmaps4rails gem to display a map of items in a fancybox.
I followed carefully the remarks on the wiki concerning ajax call, i.e. scripts have to be included manually in the application layout, maps have to be loaded in a javascript (see gem wiki).
But I still not succeed completely to make the map displayed in the box.
On the other hand as I hard code coordinates in the javascript it works fine, the map is displayed in the fancybox and the markers appear.
Let me recap.
In my index view, I have a ajax call to the items index action:
<%= link_to "Show Map", items_path(:format => :js, :show_map => true), :remote => true, :class => 'fancybox' %>
In the controller, I populate the map data:
def index
#items=Item.all
if params[:show_map]
#map= #items.to_gmaps4rails
end
end
in the index.js.erb file, I put
<% if params[:show_map] %>
var content = "<%= escape_javascript( gmaps({:last_map => false})) %>";
$.fancybox({
'content': content,
'padding' : 20
});
Gmaps.map = new Gmaps4RailsGoogle();
Gmaps.load_map = function() {
Gmaps.map.initialize();
Gmaps.map.markers = <%= #map %>;
Gmaps.map.create_markers();
Gmaps.map.adjustMapToBounds();
Gmaps.map.callback();
};
Gmaps.loadMaps();
<% else %>
// blablabla
<% end %>
Where the markers are provided in the map object.
This does not work and instead of my map I got in the fancybox the code itself appearing.
Something like:
var content = "\n
\n
<\/div>\n<\/div>\n"; $.fancybox({ 'content': content, 'padding' : 20 }); Gmaps.map = new Gmaps4RailsGoogle(); Gmaps.load_map = function() {Gmaps.map.initialize();
//Gmaps.map.markers = [{"lat":50.294,"lng":5.857},{"lat":50.294,"lng":5.857},{"lat":50.548,"lng":4.918},{"lat":50.384,"lng":3.649},{"lat":50.384,"lng":3.649},{"lat":50.08,"lng":4.5760000000000005},{"lat":50.054,"lng":5.195}];
Gmaps.map.markers = [{"lat":50.8483059,"lng":4.351783999999999},{"lat":50.496,"lng":5.066},{"lat":50.11,"lng":5.003},{"lat":50.11,"lng":5.003},{"lat":50.162,"lng":5.871},{"lat":50.08,"lng":4.5760000000000005},{"lat":50.08,"lng":4.5760000000000005},{"lat":50.08,"lng":4.5760000000000005}];
Gmaps.map.create_markers(); Gmaps.map.adjustMapToBounds(); Gmaps.map.callback(); }; Gmaps.loadMaps();
When instead of the erb <%= #map %>, I hard code the markers, for instance:
Gmaps.map.markers = [{"lat":50.294,"lng":5.857},"lat":50.294,"lng":5.857},{"lat":50.548,"lng":4.918}];
It works!
Seems like I'm missing something in the json data type conversion. But I'm not expert to find what is going wrong.
Thanks for your help!
Just successfully tried:
Open
<div id="test" style="display:none;width:300px;">
<%= gmaps markers: { data: #json } , last_map: false %>
</div>
<script type="text/javascript">
$(".fancybox").fancybox({
openEffect : 'none',
closeEffect : 'none',
afterLoad : function() { Gmaps.loadMaps(); }
});
</script>
Ok, I've got what was not going well. Thanks to the following answer https://stackoverflow.com/a/12219016/1100674.
As I use the following syntax:
Gmaps.map.markers = <%= #map %>;
I get the json rendered as this:
Gmaps.map.markers = [{"lat":50.8483059,"lng":4.351783999999999},{"lat":50.11,"lng":5.003},{"lat":50.11,"lng":5.003},{"lat":50.08,"lng":4.5760000000000005},{"lat":50.08,"lng":4.5760000000000005},{"lat":50.08,"lng":4.5760000000000005},{"lat":50.413,"lng":4.371}];
Whereas I use the raw() method,
Gmaps.map.markers = <%= raw(#map) %>;
I get the correct format.
Gmaps.map.markers = [{"lat":50.8483059,"lng":4.351783999999999},{"lat":50.11,"lng":5.003},{"lat":50.11,"lng":5.003},{"lat":50.08,"lng":4.5760000000000005},{"lat":50.08,"lng":4.5760000000000005},{"lat":50.08,"lng":4.5760000000000005},{"lat":50.413,"lng":4.371}];

gmaps4rails single marker auto zoom

I am trying to follow the answer here to zoom out a bit (by default) when a single marker is displayed on the map. I have tried the code below, and have a working map generating, but changing setZoom has no effect. Also, I receive the following error from firebug (below code).
<%= gmaps("markers" => {"data" => #json, "options" => {"auto_zoom" => false} }) %>
<% content_for :scripts do %>
<script type="text/javascript" charset="utf-8">
function gmaps4rails_callback() {
if (Gmaps4Rails.markers.length == 1) {
//only one marker, choose the zoom level you expect
Gmaps4Rails.map.setZoom(5);
}
else{
//more than one marker, let's auto_zoom
Gmaps4Rails.map_options.auto_zoom = true;
Gmaps4Rails.adjust_map_to_bounds();
}
}
</script>
<% end %>
The only error says:
TypeError: Yc is not a function
[Break On This Error]
...=b}Rf[F].Fa=xk(7,Yc("f"));me[F].cb=xk(3,function(a){var b;if(b=a.ca[ec]()?j:a.ca...
Ok, the interface changed a lot since I posted the answer you quote.
<%= gmaps("markers" => {"data" => #json, "options" => {"auto_zoom" => false} }) %>
<% content_for :scripts do %>
<script type="text/javascript" charset="utf-8">
Gmaps.map.callback = function() {
if (Gmaps.map.markers.length == 1) {
//only one marker, choose the zoom level you expect
setTimeout(function() { Gmaps.map.serviceObject.setZoom(5);}, 50);
}
else{
//more than one marker, let's auto_zoom
Gmaps.map.map_options.auto_zoom = true;
Gmaps.map.adjustMapToBounds();
}
}
</script>
<% end %>

Problems with Gmaps.map.replaceMarkers: Gmaps.map is undefined

I am trying to dynamically change the markers in Gmaps4Rails based on a user search form. I am using the code below.
The problem I am encountering is that the call to Gmaps.map.replaceMarkers within $('#locations_search').submit gives an error: Gmaps.map is undefined.
I checked using the javascript debbuger, and indeed once I enter the submit function (I have a breakpoint there), Gmaps.map is undefined. When stopping with a breakpoint in the first lines of Gmaps.map.callback, the object Gmaps.map is defined.
Probably I am missing something. It seems to be some variable scope problem here?
Gmaps.map.callback = function() {
var firstMarker = Gmaps.map.markers[0];
var map = Gmaps.map.map;
firstMarker.infowindow.open(map, firstMarker.serviceObject);
$('#locations_search').submit(function () {
var url = '/locations.json/?' + $(this).serialize();
$.getJSON(url, function(data){
Gmaps.map.replaceMarkers(data);
});
$.get(this.action, $(this).serialize(), null, 'script');
return false;
});
}
Thanks a lot!
It's just a question of script order.
Gmaps.map is created in your view when
You call either gmaps or gmaps4rails helpers.
Solution:
Add your scripts after your call to the gem's helpers
wrap your js code in <% content_for :scripts do %> code <% end %>
in your view:
<%= gmaps(...) %>
<% content_for :scripts do %>
<script type="text/javascript">
Gmaps.map.callback = function() { ... }
</script>
<% end %>
Gmaps.map.callback = function() {
var namespace = Gmaps.map;
var firstMarker = namespace.markers[0];
var map = namespace.map;
firstMarker.infowindow.open(map, firstMarker.serviceObject);
$('#locations_search').submit(function () {
var url = '/locations.json/?' + $(this).serialize();
$.getJSON(url, function(data){
namespace.replaceMarkers(data);
});
$.get(this.action, $(this).serialize(), null, 'script');
return false;
});
}

Dynamic menu select Rails don't work

I'm trying to build a chained select menu. This is the tutorial I used: http://railscasts.com/episodes/88-dynamic-select-menus
Something goes wrong, I don't know what I'm missing.
javascript
var sottocategorie = new Array();
<% for element in #sottocategorie -%>
sottocategorie.push(new Array(<%= element.idcategoria %>, <%= element.c2 %>));
<% end -%>
function selezionacategoria() {
categoriaid = $('segnalazione_categoria1').getValue();
options = $('segnalazione_categoria2').options;
options.length = 1;
sottocategorie.each(function(elementement) {
if (element[0] == categoriaid) {
options[options.length] = new Option(element[1]);
}
});
if (option.length == 1) {
$('sottocategoria_field').hide();
} else {
$('sottocategoria_field').show();
}
}
document.observe('dom:loaded', function() {
//selezionacategoria();
$('segnalazione_categoria1').observe('change', selezionacategoria);
});
html
<label for="segnalazione_categoria1">Categoria:</label>
<%= f.collection_select :categoria1, Categorium.find(:all), :id, :c1, :prompt => "Seleziona categoria" %>
<p id="sottocategoria_field">
<label for="segnalazione_categoria2">Categoria:</label>
<%= f.collection_select :categoria2, Sottocategoria1.find(:all), :id, :c2, :prompt => "Seleziona sottocategoria" %>
</p>
routes:
match '/:controller(/:action(/:id))'
The chained select menu doesn't run, the "filter" doesn't work, and also
if (option.length == 1) {
$('sottocategoria_field').hide();
} else {
$('sottocategoria_field').show();
}
doesn't work.
SOLUTION:
I've changed the javascript file using jQuery:
var sottocategorie = new Array();
<% for sottocategoria in #sottocategorie %>
sottocategorie.push(new Array('<%= sottocategoria.idcategoria %>', '<%= escape_javascript(sottocategoria.c2) %>', <%= sottocategoria.id %>));
<% end %>
function menuSelected(orig_menu, new_menu, item_array) {
orig_value = $('#segnalazione_categoria1 :selected').text();
//alert(orig_value);
$(new_menu).empty();
jQuery.each(item_array, function(i, val) {
if (val[0] == orig_value) {
$(new_menu).append($("<option></option>").attr("value",val[2]).text(val[1]));
}
});
}
$(document).ready(function(){
//bind the click event to the city submit button
$('#submit_button').bind('click', function () {
menuSelected('#segnalazione_categoria1', '#segnalazione_categoria2', sottocategorie);
});
});
SOLUTION WITH THREE LEVELS OF CHAINING:
var sottocategorie = new Array();
var subsottocategorie = new Array();
<% for sottocategoria in #sottocategorie %>
sottocategorie.push(new Array('<%= sottocategoria.idcategoria %>', '<%= escape_javascript(sottocategoria.c2) %>', <%= sottocategoria.id %>));
<% end %>
<% for subsottocategoria in #subsottocategorie %>
subsottocategorie.push(new Array('<%= subsottocategoria.idsottocategoria1s %>', '<%= escape_javascript(subsottocategoria.c3) %>', <%= subsottocategoria.id %>));
<% end %>
function menuSelected(orig_menu, new_menu, item_array) {
orig_value = $(''+ orig_menu + ' :selected').text();
//alert(orig_value);
$(new_menu).empty();
jQuery.each(item_array, function(i, val) {
if (val[0] == orig_value) {
$(new_menu).append($("<option></option>").attr("value",val[1]).text(val[1]));
}
});
}
$(document).ready(function(){
$(".nascosto").hide();
$(".nascosto1").hide();
//bind the click event to the city submit button
$('#segnalazione_categoria1').bind('click', function () {
$(".nascosto").show();
$('#segnalazione_categoria3').empty();
menuSelected('#segnalazione_categoria1', '#segnalazione_categoria2', sottocategorie);
});
$('#segnalazione_categoria2').bind('click', function (event) {
$(".nascosto1").show();
menuSelected('#segnalazione_categoria2', '#segnalazione_categoria3', subsottocategorie);
});
});

Resources