gmaps4rails - Drop a marker and update fields attribute in a form - ruby-on-rails-3

I'm trying to implement this, from the gem wiki https://github.com/apneadiving/Google-Maps-for-Rails/wiki/Javascript-goodies
<% content_for :scripts do %>
<script type="text/javascript" charset="utf-8">
var markersArray = [];
// On click, clear markers, place a new one, update coordinates in the form
Gmaps.map.callback = function() {
google.maps.event.addListener(Gmaps.map.map, 'click', function(event) {
clearOverlays();
placeMarker(event.latLng);
updateFormLocation(event.latLng);
});
};
// Update form attributes with given coordinates
function updateFormLocation(latLng) {
$('location_attributes_latitude').value = latLng.lat();
$('location_attributes_longitude').value = latLng.lng();
$('location_attributes_gmaps_zoom').value = Gmaps.map.map.getZoom();
}
// Add a marker with an open infowindow
function placeMarker(latLng) {
var marker = new google.maps.Marker({
position: latLng,
map: Gmaps.map.map,
draggable: true
});
markersArray.push(marker);
// Set and open infowindow
var infowindow = new google.maps.InfoWindow({
content: '<div class="popup"><h2>Awesome!</h2><p>Drag me and adjust the zoom level.</p>'
});
infowindow.open(Gmaps.map.map,marker);
// Listen to drag & drop
google.maps.event.addListener(marker, 'dragend', function() {
updateFormLocation(this.getPosition());
});
}
// Removes the overlays from the map
function clearOverlays() {
if (markersArray) {
for (var i = 0; i < markersArray.length; i++ ) {
markersArray[i].setMap(null);
}
}
markersArray.length = 0;
}
</script>
<% end %>
But with no luck...I'm guessing its more of an issue with the name/id of my field(s), pardon my javascript knowledge.
I've changed the fields to update with the coordinates:
function updateFormLocation(latLng) {
$('location[lat]').value = latLng.lat();
...
}
But the field doesn't get updated:
= simple_form_for :location do |l|
= l.input :lat
...
Am I missing something? Thanks!

By the look of it, that syntax is written for prototype. If you're using rails 3.1 with jQuery, you'll need to update that syntax to find your DOM nodes.
i.e. if you're looking for an element with id "location_attributes_latitude", you need to use:
$('#location_attributes_latitude')
And in order to set the value:
$('#location_attributes_latitude').val(latLng.lat());

If you only need to drop an update exist marker, just only need to do this
location_gmaps = () ->
Gmaps.map.callback = () ->
google.maps.event.addListener Gmaps.map.markers[0].serviceObject, 'dragend', (event) ->
updateFormLocationEventos(event.latLng)
# Update form attributes with given coordinates
updateFormLocationEventos = (point) ->
$('#event_position_latitude').val(point.lat())
$('#event_position_longuitude').val(point.lng())
I hope this help you

Related

odoo, how to reload widget on every db record form view?

Hi this question is related with my own answer here the thing is that the widget run only once, when the first database record object is show on the form view, but when I change to another record, the view its not updated with the actual record. I think that is because I run all the code in the ´start´ but I dont know how and where put he code to do this.
the code again:
(function (instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
openerp.chess_base = function (instance, local) {
local.ShowBoard = instance.web.form.FormWidget.extend({
start: function () {
this.$el.append('<div id="board" style="width: 300px">BOARD GOES HERE</div>');
this.show_board();
},
show_board: function () {
var Game = new instance.web.Model("chess.game"),
record_id = this.field_manager.datarecord.id,
record_name = this.field_manager.datarecord.name,
self = this;
self.el_board = self.$('#board');
Game.query(['pgn']).filter([['id', '=', record_id], ['name', '=', record_name]]).all().then(function (data) {
console.log(data);
self.cfg = {
position: data[0].pgn,
orientation: 'white',
pieceTheme: '/chess_base/static/img/chesspieces/wikipedia/{piece}.png'
};
ChessBoard(self.el_board, self.cfg);
});
}
});
instance.web.form.custom_widgets.add('board', 'instance.chess_base.ShowBoard');
}
})(openerp);
In your start function:
this._ic_field_manager.on('view_content_has_changed', this, function() {
'put your code here'
})
EDIT:
Actually there's another event you could listen, 'load_record'.
Because 'view_content_has_changed' is triggered every time a single field in the view is modified, and you maybe don't want this behavior.

gmaps4rails v2 - customize sidebar

I use gmaps4rails to display markers on a map and i have a sidebar witch allow me to select a marker and open it on my map.
the sidebar wirks well but i would like to customize it.
Right know i do:
<script type="text/javascript">
$(document).ready(function(){
var raw_markers = <%=raw #hash.to_json %>;
function createSidebarLi(json){
return ("<li>" + json.titre + ' ' + json.address + "</li>");
};
function bindLiToMarker($li, marker){
$li.on('click', function(){
handler.getMap().setZoom(14);
marker.setMap(handler.getMap()); //because clusterer removes map property from marker
marker.panTo();
google.maps.event.trigger(marker.getServiceObject(), 'click');
});
};
function createSidebar(json_array){
_.each(json_array, function(json){
var $li = $( createSidebarLi(json) );
$li.appendTo('#markers_list');
bindLiToMarker($li, json.marker);
});
};
handler = Gmaps.build('Google', { builders: { Marker: InfoBoxBuilder} });
handler.buildMap({ internal: {id: 'map'}}, function(){
var markers = handler.addMarkers(raw_markers);
_.each(raw_markers, function(json, index){
var marker = markers[index];
json.marker = marker;
google.maps.event.addListener(handler.getMap(), "click", function(){
infoWindow.close();
});
google.maps.event.addListener(marker.getServiceObject(), 'mouseover', function(){
google.maps.event.trigger(marker.getServiceObject(), 'click');
});
});
createSidebar(raw_markers);
handler.bounds.extendWith(markers);
handler.fitMapToBounds();
});
});
</script>
I'd like to create a partial and display it instead of just:
return ("<li>" + json.titre + ' ' + json.address + "</li>");
In my partial, i'd like to do the same as my custom infowindow.
IN my controller, i use:
marker.infowindow render_to_string(:partial => "/properties/infowindow", :locals => { :property => property})
Is there a way to do that with the sidebar ? I used to do "marker.sidebar render_to_string" it with gmaps4rails v1 but it doesn't work anymore.
Its just javascript.
First, provide the data in your controller, where you generate json (I assume you use the builtin json generator):
marker.json({
sidebar: render_to_string(:partial => "/properties/infowindow", :locals => { :property => property})
})
Then display it:
function createSidebarLi(json){
return json.sidebar;
};

Reverse Geocoding With Dynamic Form

I've been trying to find a way to use the 'Reverse Geocoding' service with the Latitude and Longitude co-ordinates coming from two text boxes on my HTML form, and I must admit I'm not really sure what I need to do.
I have managed to do this with the 'Geocode' service (see code below), but I just wondered whether someone may be able to point me in the right direction of how I could adapt the 'Geocode' javascript I have to the 'Reverse Geocoging' service.
(function Geocode() {
// This is defining the global variables
var map, geocoder, myMarker;
window.onload = function() {
//This is creating the map with the desired options
var myOptions = {
zoom: 5,
center: new google.maps.LatLng(55.378051,-3.435973),
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.BOTTOM
},
navigationControl: true,
navigationControlOptions: {
style: google.maps.NavigationControlStyle.ZOOM_PAN,
position: google.maps.ControlPosition.TOP_RIGHT
},
scaleControl: true,
scaleControlOptions: {
position: google.maps.ControlPosition.BOTTOM_LEFT
}
};
map = new google.maps.Map(document.getElementById('map'), myOptions);
// This is making the link with the 'Search For Location' HTML form
var form = document.getElementById('SearchForLocationForm');
// This is catching the forms submit event
form.onsubmit = function() {
// This is getting the Address from the HTML forms 'Address' text box
var address = document.getElementById('GeocodeAddress').value;
// This is making the Geocoder call
getCoordinates(address);
// This is preventing the form from doing a page submit
return false;
}
}
// This creates the function that will return the coordinates for the address
function getCoordinates(address) {
// This checks to see if there is already a geocoded object. If not, it creates one
if(!geocoder) {
geocoder = new google.maps.Geocoder();
}
// This is creating a GeocoderRequest object
var geocoderRequest = {
address: address
}
// This is making the Geocode request
geocoder.geocode(geocoderRequest, function(results, status) {
// This checks to see if the Status is 'OK 'before proceeding
if (status == google.maps.GeocoderStatus.OK) {
// This centres the map on the returned location
map.setCenter(results[0].geometry.location);
// This creates a new marker and adds it to the map
var myMarker = new google.maps.Marker({
map: map,
zoom: 12,
position: results[0].geometry.location,
draggable:true
});
//This fills out the 'Latitude' and 'Longitude' text boxes on the HTML form
document.getElementById('Latitude').value= results[0].geometry.location.lat();
document.getElementById('Longitude').value= results[0].geometry.location.lng();
//This allows the marker to be draggable and tells the 'Latitude' and 'Longitude' text boxes on the HTML form to update with the new co-ordinates as the marker is dragged
google.maps.event.addListener(
myMarker,
'dragend',
function() {
document.getElementById('Latitude').value = myMarker.position.lat();
document.getElementById('Longitude').value = myMarker.position.lng();
var point = myMarker.getPosition();
map.panTo(point);
}
);
}
}
)
}
})();
UPDATE
Firstly, many thanks for the code you kindly posted and the suggestion to go and have a look at the Google documentation.
From what you suggested, and from what I took from the additional documentation I came up with the following. However, when I click my submit button nothing happens, almost as if there is no command attached to it. I don't receive any error messages and I've checked to make sure that I've linked the code to the correct fieldnames and all seems ok. I just wondered whether it would be at all possible if you, or indeed anyone else, could take a look at it please to tell me where I've gone wrong.
Many thanks and kind regards
(function ReverseGeocode() {
var form, geocoderRequest, latlng, myMarker, point;
window.onload = function() {
//This is creating the map with the desired options
var myOptions = {
zoom: 5,
center: new google.maps.LatLng(55.378051,-3.435973),
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.BOTTOM
},
navigationControl: true,
navigationControlOptions: {
style: google.maps.NavigationControlStyle.ZOOM_PAN,
position: google.maps.ControlPosition.TOP_RIGHT
},
scaleControl: true,
scaleControlOptions: {
position: google.maps.ControlPosition.BOTTOM_LEFT
}
};
map = new google.maps.Map(document.getElementById('map'), myOptions);
var latlng = new google.maps.LatLng('Latitude', 'Longitude');
// This is making the Geocode request
geocoder.geocode({'LatLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
map.setZoom(11);
var myMarker = new google.maps.Marker({
position: results[0].geometry.location,
map: map
});
//This fills out the 'Address' text boxe on the HTML form
document.getElementById('Address').value= results[0].geometry.location.latlng();
var point = myMarker.getPosition();
map.panTo(point);
}
}
}
)}})
Once you have the latitude and longitude from your form, you do something like this (using your above code as a starting point, for the sake of clarity):
var latlng = new google.maps.LatLng(latitudeFromForm,longitudeFromForm);
// This is creating a GeocoderRequest object
var geocoderRequest = {
'latlng':latlng
}
// This is making the Geocode request
geocoder.geocode(geocoderRequest, function(results, status) {
// This checks to see if the Status is 'OK 'before proceeding
if (status == google.maps.GeocoderStatus.OK) {
// Do stuff with the result here
}
If you haven't read it yet, you may want to read the Reverse Geocoding section of http://code.google.com/apis/maps/documentation/javascript/services.html#ReverseGeocoding.

Dojo populate combo box widget dynamically

Could someone please explain to me why this simple straight forward code isnt working,
var serviceStore = new dojo.data.ItemFileWriteStore({
data: {identifier: "serviceCode",items:[]}
});
//jsonObj is a json object that I obtain from the server via AJAX
for(var i = 0; i<jsonObj.length;i++){
serviceStore.newItem({serviceCode: jsonObj[i]});
}
var serviceFilterSelect = dojo.byId('serviceSelect');
serviceFilterSelect.store = serviceStore;
There is no error at all displayed but my combobox with the id "serviceSelect" doesn't display any options, the combo is declared in the html section of my code,
<input dojoType = "dijit.form.ComboBox" id="serviceSelect"></input>
Any pointers towards the right direction will be much appreciated.
First of all you should use dijit.byId to get dojo widget instead of dojo.byId.
Also every item in jsonObj should contains field "name". This field will be displayed in combobox. E.g:
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require("dijit.form.ComboBox");
var storeData = {
identifier: 'serviceCode',
items: []
}
var jsonObj = [{
serviceCode: 'sc1',
name: 'serviceCode1'
},
{
serviceCode: 'sc2',
name: 'serviceCode2'
}]
dojo.addOnLoad(function () {
var serviceStore = new dojo.data.ItemFileWriteStore({ data: storeData });
for (var i = 0; i < jsonObj.length; i++) {
serviceStore.newItem(jsonObj[i]);
}
var serviceFilterSelect = dijit.byId('serviceSelect');
serviceFilterSelect.attr('store', serviceStore);
});
And HTML:
<select dojotype="dijit.form.ComboBox" id="serviceSelect" ></select>
It seems that it works.
I can't tell from the code you posted, but if you're having trouble getting the DOM nodes, they may not had a chance to get loaded.
You can try wrapping what you have above with a dojo.ready(function(){ ... });.
Have you put items in your store? I can't tell from the sample that you posted.
var serviceStore = new dojo.data.ItemFileWriteStore({
data: {
identifier: "serviceCode"
,items: [
{serviceCode:'ec', name:'Ecuador'}
,{serviceCode:'eg', name:'Egypt'}
,{serviceCode:'sv', name:'El Salvador'}
]
}
});
For dojo >= 1.6:
dojo.byId('serviceSelect').store=serviceStore;
For dojo < 1.6:
dojo.byId('serviceSelect').attr("store",serviceStore);

How to refilter a dojo DataGrid?

I have a DataGrid that I already filtered using grid.filter(query, rerender). If I add another item, after calling save() I see the new item in the grid even though it shouldn't display because of the filter. I'm thinking "ok, I'll just filter it again when the store finishes saving. But after calling grid.filter with the same query all the rows disappear. Any ideas what I might be doing wrong?
Code to filter the grid:
var filterQuery = dijit.byId("filterTextbox").attr("value");
var grid = dijit.byId("grid");
var queryValue = "*";
if(filterQuery != ""){
queryValue += filterQuery + "*";
}
grid.filter({name: queryValue}, true);
Code to add new items to the grid
function addItemToGrid(newItemName){
var newItem = {name: newItemName};
var grid = dijit.byId("grid");
var store = grid.store;
store.addItem(newItem);
store.save();
}
Try to use:
store.newItem(newItem);
instead of store.addItem(newItem);
(addItem is not a standard method to add items into store)
Inside of your addItemToGrid function, try adding an onComplete listener to your save method and sort or filter the grid in the onComplete function
store.save({onComplete: function() {
grid.filter({name: queryValue}, true);
}
});
I had the same problem and only managed to fix it by running the grid filter periodically in the background with the help of some jQuery. Here is some sample code; hope this helps someone else having problems with this.
// ADD JQUERY
<script src="http://code.jquery.com/jquery-latest.js"></script>
.
// PUT THIS IN THE <HEAD> OF THE PAGE
<script type="text/javascript">
$(document).ready(function() {
function filterTheDataGrid() {
if (dijit.byId("grid") != undefined) {
dijit.byId("grid").filter({color: "Red"});
}
}
// RUN THE filterTheDataGrid FUNCTION EVERY ONE SECOND (1000 MILLISECONDS) //
// LOWER '1000' FOR FASTER REFRESHING, MAYBE TO 500 FOR EVERY 0.5 SECOND REFRESHES //
var refreshDataGrid = setInterval(function() { filterTheDataGrid(); }, 1000);
}
</script>
.
// PUT THIS IN THE <HEAD> OF THE PAGE
<script type="text/javascript">
// SETUP THE LAYOUT FOR THE DATA //
var layoutItems = [[
{
field: "id",
name: "ID",
width: '5px',
hidden: true
},
{
field: "color",
name: "Color",
width: '80px'
}
]];
// Create an empty datastore //
var storeData = {
identifier: 'id',
label: 'id',
items: []
}
var store3 = new dojo.data.ItemFileWriteStore( {data : storeData} );
</script>
.
// PUT THIS IN THE <HTML> OF THE PAGE
<div id="grid" dojoType="dojox.grid.DataGrid" jsId="grid5" store="store3" structure="layoutItems" query="{ type: '*' }" clientSort="true" rowsPerPage="40"></div>
.
<script type="text/javascript">
function addItemToGrid(formdata) {
// THIS FUNCTION IS CALLED BY A DIALOG BOX AND GETS FORM DATA PASSED TO IT //
var jsonobj = eval("(" + dojo.toJson(formData, true) + ")");
var myNewItem = {
id: transactionItemID,
color: jsonobj.color
};
// Insert the new item into the store:
store3.newItem(myNewItem);
store3.save({onComplete: savecomplete, onError: saveerror});
}
</script>