@if (RenderSelect)
{
|
- ToggleRowSelection(item[SelectionField].ToString()??string.Empty)" />
+ @{
+ string rowId = string.Empty;
+ if (item.TryGetValue(SelectionField, out var idObj) && idObj is not null)
+ {
+ rowId = idObj.ToString() ?? string.Empty;
+ }
+ }
+ ToggleRowSelection(rowId)" />
|
}
@@ -232,7 +238,7 @@
public bool SelectAll { get; set; } = false;
public Dictionary SortDirections { get; set; } = new Dictionary();
private List> PaginatedData { get; set; } = new List>();
- private List SelectedRowIndexes = new List();
+ private HashSet SelectedRowIndexes = new HashSet();
private List> SelectRows => GetSelectedRows();
public event Action>>? OnGetSelectedRows;
#endregion
@@ -292,10 +298,13 @@
{
foreach (var item in Data)
{
- string? rowId = item[SelectionField]?.ToString();
- if (rowId != null && !SelectedRowIndexes.Contains(rowId))
+ if (item.TryGetValue(SelectionField, out var idObj) && idObj is not null)
{
- SelectedRowIndexes.Add(rowId);
+ var rowId = idObj.ToString();
+ if (rowId is not null && !SelectedRowIndexes.Contains(rowId))
+ {
+ SelectedRowIndexes.Add(rowId);
+ }
}
}
}
@@ -338,8 +347,22 @@
}
private void PaginateData()
{
+ IEnumerable> source = Data ?? Enumerable.Empty>();
+ if (!string.IsNullOrWhiteSpace(SearchTerm) && Columns?.Count > 0)
+ {
+ var term = SearchTerm;
+ source = source.Where(row => Columns.Any(col => {
+ if (!row.TryGetValue(col, out var val) || val is null) return false;
+ return val.ToString().IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0;
+ }));
+ }
+ if (!string.IsNullOrEmpty(SortedColumn))
+ {
+ bool asc = SortDirections.ContainsKey(SortedColumn) ? SortDirections[SortedColumn] : true;
+ source = asc ? source.OrderBy(_ => _[SortedColumn]) : source.OrderByDescending(_ => _[SortedColumn]);
+ }
int startIndex = (CurrentPage - 1) * RowsPerPage;
- PaginatedData = Data.Skip(startIndex).Take(RowsPerPage).ToList();
+ PaginatedData = source.Skip(startIndex).Take(RowsPerPage).ToList();
}
private void ChangePage(int pageNumber)
{
diff --git a/phronCare.UIBlazor/wwwroot/js/phmap.js b/phronCare.UIBlazor/wwwroot/js/phmap.js
index 31498fd..2be5d49 100644
--- a/phronCare.UIBlazor/wwwroot/js/phmap.js
+++ b/phronCare.UIBlazor/wwwroot/js/phmap.js
@@ -1,51 +1,153 @@
window.phMap = {
+ _maps: {},
+ _searchAbortController: null,
+
initMap: function (mapId, lat, lng, zoom) {
- const map = L.map(mapId).setView([lat, lng], zoom);
-
- L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
- attribution: '© OpenStreetMap contributors'
- }).addTo(map);
-
- const marker = L.marker([lat, lng]).addTo(map)
- .bindPopup('Ubicación inicial')
- .openPopup();
-
- // Guardamos el mapa y el marcador
- window._phMaps = window._phMaps || {};
- window._phMaps[mapId] = { map, marker };
-
- map.on('click', function (e) {
- const newLat = e.latlng.lat;
- const newLng = e.latlng.lng;
-
- // Mover el marcador existente
- window._phMaps[mapId].marker.setLatLng([newLat, newLng]);
- window._phMaps[mapId].marker.getPopup().setContent('Nueva ubicación').openOn(map);
-
- // Llamar al método en Blazor
- DotNet.invokeMethodAsync('phronCare.UIBlazor', 'NotifyLocationChanged', newLat, newLng);
- });
-
- },
- searchAddress: async function (mapId, address) {
- const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(address)}`);
- const data = await response.json();
-
- if (data.length === 0) {
- alert("Dirección no encontrada.");
+ // Evitar reinicializar si ya existe
+ if (this._maps[mapId]) {
+ console.warn(`Map ${mapId} already initialized`);
return;
}
- const lat = parseFloat(data[0].lat);
- const lon = parseFloat(data[0].lon);
+ try {
+ const map = L.map(mapId, {
+ zoomControl: true,
+ attributionControl: true
+ }).setView([lat, lng], zoom);
+
+ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
+ attribution: '© OpenStreetMap contributors',
+ maxZoom: 19,
+ crossOrigin: true
+ }).addTo(map);
+
+ const marker = L.marker([lat, lng], {
+ draggable: false,
+ keyboard: false
+ }).addTo(map)
+ .bindPopup(`Lat: ${lat.toFixed(5)}
Lng: ${lng.toFixed(5)}`)
+ .openPopup();
+
+ this._maps[mapId] = {
+ map,
+ marker,
+ clickHandler: this._createClickHandler.bind(this, mapId)
+ };
+
+ // Agregar event listener para clicks en el mapa
+ map.on('click', this._maps[mapId].clickHandler);
+
+ // Resizable map
+ map.invalidateSize();
+ } catch (error) {
+ console.error(`Error initializing map ${mapId}:`, error);
+ }
+ },
+
+ _createClickHandler: function (mapId, e) {
+ const newLat = e.latlng.lat;
+ const newLng = e.latlng.lng;
+ const mapData = this._maps[mapId];
- const mapData = window._phMaps[mapId];
if (!mapData) return;
- mapData.map.setView([lat, lon], 15);
- mapData.marker.setLatLng([lat, lon]);
- mapData.marker.getPopup().setContent(address.toUpperCase()).openOn(mapData.map);
+ mapData.marker.setLatLng([newLat, newLng]);
+ mapData.marker.setPopupContent(`Lat: ${newLat.toFixed(5)}
Lng: ${newLng.toFixed(5)}`);
+ mapData.marker.getPopup().setLatLng([newLat, newLng]);
- DotNet.invokeMethodAsync('phronCare.UIBlazor', 'NotifyLocationChanged', lat, lon);
+ if (typeof DotNet !== 'undefined' && DotNet.invokeMethodAsync) {
+ DotNet.invokeMethodAsync('phronCare.UIBlazor', 'NotifyLocationChanged', newLat, newLng)
+ .catch(error => console.error('Error invoking Blazor method NotifyLocationChanged:', error));
+ } else {
+ console.warn('DotNet interop not available');
+ }
+ },
+
+ updateLocation: function (mapId, lat, lng) {
+ const mapData = this._maps[mapId];
+ if (!mapData) {
+ console.warn(`Map ${mapId} not found`);
+ return;
+ }
+
+ mapData.map.setView([lat, lng], mapData.map.getZoom());
+ mapData.marker.setLatLng([lat, lng]);
+ mapData.marker.setPopupContent(`Lat: ${lat.toFixed(5)}
Lng: ${lng.toFixed(5)}`);
+ },
+
+ searchAddress: async function (mapId, address) {
+ const mapData = this._maps[mapId];
+ if (!mapData) {
+ console.warn(`Map ${mapId} not found`);
+ return;
+ }
+
+ // Cancelar búsquedas anteriores
+ if (this._searchAbortController) {
+ this._searchAbortController.abort();
+ }
+ this._searchAbortController = new AbortController();
+
+ try {
+ const response = await fetch(
+ `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(address)}`,
+ {
+ signal: this._searchAbortController.signal,
+ headers: {
+ 'Accept': 'application/json'
+ }
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`API error: ${response.status}`);
+ }
+
+ const data = await response.json();
+
+ if (!data || data.length === 0) {
+ console.warn(`Address not found: ${address}`);
+ return;
+ }
+
+ const lat = parseFloat(data[0].lat);
+ const lon = parseFloat(data[0].lon);
+
+ if (isNaN(lat) || isNaN(lon)) {
+ console.error('Invalid coordinates from API');
+ return;
+ }
+
+ mapData.map.setView([lat, lon], 15);
+ mapData.marker.setLatLng([lat, lon]);
+ mapData.marker.setPopupContent(`${address}
Lat: ${lat.toFixed(5)}
Lng: ${lon.toFixed(5)}`);
+
+ if (typeof DotNet !== 'undefined' && DotNet.invokeMethodAsync) {
+ DotNet.invokeMethodAsync('phronCare.UIBlazor', 'NotifyLocationChanged', lat, lon)
+ .catch(error => console.error('Error invoking Blazor method NotifyLocationChanged:', error));
+ } else {
+ console.warn('DotNet interop not available');
+ }
+
+ } catch (error) {
+ if (error.name === 'AbortError') {
+ console.log('Search cancelled');
+ } else {
+ console.error('Search error:', error);
+ }
+ }
+ },
+
+ destroyMap: function (mapId) {
+ const mapData = this._maps[mapId];
+ if (!mapData) return;
+
+ try {
+ mapData.map.off('click', mapData.clickHandler);
+ mapData.map.remove();
+ delete this._maps[mapId];
+ } catch (error) {
+ console.error(`Error destroying map ${mapId}:`, error);
+ }
}
};