gmaps4rails v2 - customize sidebar - gmaps4rails

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;
};

Related

Delete method with vue-tags-input Vue Js

I try to create a delete method in vue-tags-input in Vue Js. I am not sure how to get the index. from this tag. Usually in my delete method I use the index .
<vue-tags-input
v-model="tagName"
class="tags-input w-100 mt-0"
#before-deleting-tag="deleteCustomerName"
/>
deleteCustomerName: function () {
const id = this.editedItemId;
const id_c = 33; //right now I am not sure how to get id_c
// const deleted_user_name = this.customer_names[index].name;
this.boxOne = "";
this.$bvModal
.msgBoxConfirm("Are you sure that you want to delete this ?", {
okVariant: "danger",
okTitle: "Delete",
cancelTitle: "Cancel",
centered: true
})
.then(confirm => {
if (confirm) {
deleteApi("/customers/" + id + "/" + id_c).then(() => {
this.$nextTick(() => {
// this.$emit('deleted',deleted_user_name)
// this.customer_names.splice(index, 1); //usualy I do this, but now it doesn't now how index is
console.log('User deleted!');
});
});
}
})
.catch(error => {
console.log(error);
});
},
Here is describing http://www.vue-tags-input.com/#/api/events . before-deleting-tag return index,tag,deleteTag[func] so you need to set param in deleteCustomerName parameters scope .
deleteCustomerName: function (params) {
console.log(params.index)
....
}

How to dynamically render strings in Vue?

I am pulling an array on images from Netlify CMS and passing that to vue-picture-swipe component, but the acutal images don't render, even though the path is correct etc.
Not sure what I am doing wrong?
Template
vue-picture-swipe(:items="items")
Script
<script>
export default {
data: function() {
return {
items: []
};
},
created: function () {
this.imageList()
},
methods: {
imageList: function () {
const files = require.context('~/content/gallery/images/', false, /\.md$/);
let images = files.keys().map(key => ({
...files(key)
}));
let items = images.map(function(value) {
return {
'src': value.attributes.imgSrc,
'thumbnail': value.attributes.imgSrc,
'alt': value.attributes.imgDesc
}
});
return this.items = items
}
}
};
</script>
Rendered HTML
<img src="/assets/uploads/image.jpg" alt="Test Image description" itemprop="thumbnail">
According to your output, if value.attributes.imgSrc renders a relative path like src="/assets/uploads/image.jpg", try to require this path.
I'm assuming your "assets" and "components" folders are directly under "src":
let items = images.map(function(value) {
return {
'src': require('..' + value.attributes.imgSrc), // or require('#' + value.attributes.imgSrc)
'thumbnail': require('..' + value.attributes.imgSrc),
'alt': value.attributes.imgDesc
}
})
Note that vue-picture-swipe items props need w and h attributes for each item.

Is there a way to do pagination with firebase realtime database (vuejs)?

I'm trying to paginate my data from firebase realtime database.
Do I have to change to firestore ? Where all is explain in Google's doc (https://firebase.google.com/docs/firestore/query-data/query-cursors) or it's also possible with rtdb ?
Here is my code (i'm using vue js) :
loadConcerts ({commit}) {
commit('setLoading', true)
firebase.database().ref('concerts')
.orderByChild('expires')
.startAt(Date.now() / 1e3)
.limitToFirst(10)
.once('value')
.then(data => {
const concerts = []
data.forEach(element => {
concerts.push({
id: element.key,
title: element.val().title,
day: element.val().day,
ticketlink: element.val().ticketlink,
description: element.val().descriptio
})
})
commit('setLoadedConcerts', concerts)
commit('setLoading', false)
})
.catch(
(error) => {
console.log(error)
commit('setLoading', false)
}
)
},
I would like to add pagination after 10 results, or infinite scrolling.
I have also had similar problem with pagination. The documentation seems to be insufficient i.e they show you how to go to next page but not how to move back to the previous page. Its just frustrating really.
I am using firestore
Below is how i implemented a simple pagination. I have already configured VueFire , Firebase and BootstrapVue i'll head straight to the code.
What to do different that no one shows you.
Use VueFire programmatic binding instead of declarative binding see here
To get firstVisible item in firebase run documentSnapshots.docs[0]
<template>
<div>
<p>{{countries}}</p>
<b-button-group size="lg" class="mx-2">
<b-button :disabled="prev_btn" #click="previous" >«</b-button>
<b-button :disabled="next_btn" #click="next">»</b-button>
</b-button-group>
</div>
</template>
<script>
import firebase from 'firebase/app'
import 'firebase/auth'
import { db } from '../main'
export default {
name: 'Countries',
data () {
return {
countries: [],
limit: 2,
lastVisible: '',
firstVisible: '',
next_btn: false,
prev_btn: true
}
},
methods: {
next () {
if (!this.next_btn) {
// bind data with countries
this.$bind('countries', db.collection('Countries').orderBy('createdAt').startAfter(this.lastVisible).limit(this.limit))
// set last and first visible items
db.collection('Countries').orderBy('createdAt').startAfter(this.lastVisible).limit(this.limit).get().then(documentSnapshots => {
this.lastVisible = documentSnapshots.docs[documentSnapshots.docs.length - 1]
this.firstVisible = documentSnapshots.docs[0]
}).then(() => {
// Peep on the next next query to see if it gives zero
db.collection('Countries').orderBy('createdAt').startAfter(this.lastVisible).limit(this.limit).get()
.then(snap => {
if (snap.size === 0) {
//disable button if the next peeped result gets zero
this.next_btn = true
// enable previous button
this.prev_btn = false
} else {
// enable next button if peeped result is not zero
this.next_btn = false
// enable previous button
this.prev_btn = false
}
})
})
}
},
previous () {
// Ensure previous is not zero
db.collection('Countries').orderBy('createdAt').endBefore(this.firstVisible).limitToLast(this.limit).get().then(snap => { return snap.size })
.then(size => {
//confirm is not zero here
if (size !== 0) {
//bind the previous to countries
this.$bind('countries', db.collection('Countries').orderBy('createdAt').endBefore(this.firstVisible).limitToLast(this.limit))
// Set last and first visible
db.collection('Countries').orderBy('createdAt').endBefore(this.firstVisible).limitToLast(this.limit).get().then(documentSnapshots => {
this.lastVisible = documentSnapshots.docs[documentSnapshots.docs.length - 1]
this.firstVisible = documentSnapshots.docs[0]
}).then(() => {
// peep the next previous query
db.collection('Countries').orderBy('createdAt').endBefore(this.firstVisible).limitToLast(this.limit).get()
.then(snap => {
if (snap.size === 0) {
//if next peeped previous button gets 0 disable
this.prev_btn = true
this.next_btn = false
} else {
//if next peeped result is does not get 0 enable buttons
this.prev_btn = false
this.next_btn = false
}
})
})
}
})
}
},
mounted () {
// run first query and bind data
this.$bind('countries', db.collection('Countries').orderBy('createdAt').limit(this.limit))
// set last and first Visible
db.collection('Countries').orderBy('createdAt').limit(this.limit).get().then(documentSnapshots => {
this.lastVisible = documentSnapshots.docs[documentSnapshots.docs.length - 1]
this.firstVisible = documentSnapshots.docs[0]
}).then(() => {
// peep to check if next should be on or off
db.collection('Countries').orderBy('createdAt').startAfter(this.lastVisible).limit(this.limit).get()
.then(snap => {
if (snap.size === 0) {
this.next_btn = true
}
})
})
}
}
</script>

Getting reactivity from watch in Vue.js

Trying to make a component in Vue.js, which first shows image via thumbnail, loading full image in background, and when loaded, show full image.
The thing which does not work, component does not react on change of showThumb flag in watch section. What is wrong?
Vue.component('page-image',
{
props: ['data'],
template:
'<img v-if="showThumb == true" v-bind:src="thumbSrc"></img>'+
'<img v-else v-bind:src="fullSrc"></img>',
data: function()
{
return { thumbSrc: '', fullSrc: '', showThumb: true };
},
watch:
{
data: function()
{
this.thumbSrc = data.thumbImg.url;
this.fullSrc = data.fullImg.url;
this.showThumb = true;
var imgElement = new Image();
imgElement.src = this.fullSrc;
imgElement.onload = (function()
{
this.showThumb = false; // <<-- this part is broken
} );
}
}
} );
Note: there is a reason why I do it via 2 img tags - this example is simplified.
Your onload callback will have a different scope than the surrounding watch function, so you cannot set your data property like this. Change it to an arrow function to keep scope:
imgElement.onload = () =>
{
this.showThumb = false;
};
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

gmaps4rails - Drop a marker and update fields attribute in a form

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