I am developing a map in LeafLet and Laravel 6 . From a route I load all the markers that I later show on the map.
In the controller I have this method where I get all the published bookmarks.
public function getInstallations(){
$installations = Installation::where('status', 'PUBLISHED')->get();
$data = [];
foreach ($installations as $key => $value) {
$data[$key + 1] = [
'id' => $value->id,
'uuid' => $value->uuid,
'user_id' => $value->user_id,
'category_id' => $value->category_id,
'company' => $value->company,
'name' => $value->name,
'lat' => $value->lat,
'lng' => $value->lng,
'description' => $value->description,
'on_grid' => $value->on_grid,
'created_at' => $value->created_at,
'pin' => $value->pin,
];
}
return response()->json($data);
}
Then in the view in the JS part I do the following:
var map = L.map('mapid').setView([{{ config('leaflet.map_center_latitude') }}, {{ config('leaflet.map_center_longitude') }}], {{ config('leaflet.zoom_level') }});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
Variables
{{ config('leaflet.map_center_latitude') }}, {{ config('leaflet.map_center_longitude') }}], {{ config('leaflet.zoom_level') }}
I define them in a Leaflet configuration file that I have hosted in the config folder of the Laravel application.
I then access the data path from JS and store it in the getData variable:
let getData = `{{ route('getInstallations') }}`;
const api = new XMLHttpRequest();
api.open('GET', getData, true);
api.send();
var marker = {};
api.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200) {
let datos = JSON.parse(this.responseText);
$.each(datos, function(index, item) {
var instIcon = L.icon({
iconUrl: `/images/` + item.pin ,
iconSize: [22, 32], // size of the icon
iconAnchor: [11, 32], // point of the icon which will correspond to marker's location
popupAnchor: [0, -33] // point from which the popup should open relative to the iconAnchor
});
marker = new L.marker([item.lat, item.lng], {icon: instIcon})
.bindPopup('<p class="popup__header"> <strong>'+ item.name + '</strong><div class="separator-2"></div>' + '<button type="button" id="sendData" class="btn btn-success btn-sm btn-block dataModal sendData" data-toggle="modal" data-target="#dataModal" >Detalles</button> </p>' ).addTo(map);
});
$(document).ready(function(){
$(document).on('click', '.sendData', function(){
var id=$(this).val(item.id);
var selector = '.modalTitle' + item.id;
alert(selector);
var name = $(selector).text();
$(".modalTitle").html(name);
});
});
}
}
I convert the getData
to another variable datos
and loop through it to create the markers. The result is something like this:
In the construction of those pins, I define the option that they have a popup that would be shown in:
The goal is that clicking on "DETAILS" opens a bootstrap modal where you can show the record detail with its associated images.
The modal form code is from bootstrap 4:
<div class="modal fade" id="dataModal" tabindex="-1" role="dialog" aria-labelledby="dataModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title modalTitle" id="dataModalLabel"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<img class="img-fluid img-rounded" src="{{ asset('/images/generica.png') }}" alt="">
<small class="text-muted float-right mt-2">Creado por: Usuario | 2019-12-04</small>
<br><br>
<p class="mt-2">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary mt-3" data-dismiss="modal">Cerrar</button>
@auth ()
<button type="button" class="btn btn-warning mt-3">Editar</button>
@endauth
</div>
</div>
</div>
</div>
The problem I have is that I cannot send the data via that button generated in the js code... if someone can give me a hand... I would appreciate it again
Let's go by parts, first the logic of the modal comes from:
Now, let's re-formulate the code you have:
Here you define the Id and a class like
sendData
, which seems strange to me, it is recommended to avoid using the same name for ID and class, you avoid unnecessary confusion. If you are always going to be generating popups with the same, there will come a time when the DOM becomes heavy and the code can get tangled up.To debug in Sherlock Holmes mode we ask ourselves about the modal: Will it be reusable? Will I need the same Id to be kept? To better answer these questions, let's look at the following part of the code:
Let's pause here. Is document ready necessary? Not because? Because it is unnecessary to execute a method within a function that has already loaded the entire document, in other words, if we remove the document ready it will still work. And at what point do we need the document ready to be executed? Well, when the page is going to load for the first time and you need to initialize values inside
<select options>
, state variables and things like that.In the next line we find a
event listener
. We pause again and analyze: What is the purpose of this event listener? As observed, what we want to do is obtain the values of the element that has been clicked to proceed to select an ID of a fragment of the HTML code that should be present. However, there are alternatives such as the following:Generate a separate function that directly receives the ID and calls the modal instead of listening for a click event. Said in code:
And we invoke that from:
Notice that I removed the Id and the "sendData" class.
So far, we're doing fine. A first detail that worries me: From the function
verDetallesDelPopup
, we are making another selector to extract the name and put it inside ALL the elements that contain a class calledmodalTitle
, according to the code, it is in the modal at the end of the question:Since it's a single element, it would be more efficient to call it by the selector
#dataModalLabel
like so:A second fact that worries me, see the comments inside the code:
It happens that if the elements of the selector are nonexistent, it will throw an error, make sure you have them or, modify the behavior of this code so that it better adapts to what you have.
As suggested, I have done the following:
What matters is the following part:
Then in the function, I do this other:
I want to clarify that I
alert
put the one that is entering the function only to know if it enters it, well, it does not enter. On the other hand, in debugging, in the "SOURCE" tab I can see the followingFurther down at the bottom of this section I get the error with red letters:
from what it seems, since I am sending a text string, it is as if it does not know what a text is... or it is confused with the characters that are inside it since in many markers there are parentheses.
Solved, I had to put a slanted quote in the fields that are text and it was fine...
Now if the title, the description and everything else arrives in the modal... now I have to see how I recover the images, but that's another topic...