Implementieren von Zuordnungsszenarien mithilfe von AJAX
von Microsoft
Dies ist Schritt 11 eines kostenlosen "NerdDinner"-Anwendungstutorial , in dem Sie schrittweise eine kleine, aber vollständige Webanwendung mit ASP.NET MVC 1 erstellen.
Schritt 11 zeigt, wie Sie die AJAX-Zuordnungsunterstützung in unsere NerdDinner-Anwendung integrieren, sodass Benutzer, die Abendessen erstellen, bearbeiten oder anzeigen, den Ort des Abendessens grafisch anzeigen können.
Wenn Sie ASP.NET MVC 3 verwenden, empfehlen wir Ihnen, die Tutorials Erste Schritte Mit MVC 3 oder MVC Music Store zu befolgen.
NerdDinner Schritt 11: Integrieren einer AJAX-Zuordnung
Wir werden unsere Anwendung nun visuell interessanter gestalten, indem wir die Ajax-Zuordnungsunterstützung integrieren. Dadurch können Benutzer, die Abendessen erstellen, bearbeiten oder anzeigen, den Ort des Abendessens grafisch anzeigen.
Erstellen einer Teilansicht einer Karte
Wir werden die Zuordnungsfunktionalität an mehreren Stellen in unserer Anwendung verwenden. Um unseren Code trocken zu halten, kapseln wir die allgemeine Zuordnungsfunktionalität in einer einzelnen Teilvorlage, die wir für mehrere Controlleraktionen und Ansichten wiederverwenden können. Wir nennen diese Teilansicht "map.ascx" und erstellen sie im Verzeichnis \Views\Dinners.
Wir können die map.ascx partielle erstellen, indem Sie mit der rechten Maustaste auf das Verzeichnis \Views\Dinners klicken und den Menübefehl Add-View> auswählen. Wir nennen die Ansicht "Map.ascx", überprüfen sie als Teilansicht und geben an, dass sie eine stark typisierte "Dinner"-Modellklasse übergeben wird:
Wenn wir auf die Schaltfläche "Hinzufügen" klicken, wird unsere Teilvorlage erstellt. Anschließend wird die Datei Map.ascx aktualisiert, um den folgenden Inhalt zu erhalten:
<script src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2" type="text/javascript"></script>
<script src="/Scripts/Map.js" type="text/javascript"></script>
<div id="theMap">
</div>
<script type="text/javascript">
$(document).ready(function() {
var latitude = <%=Model.Latitude%>;
var longitude = <%=Model.Longitude%>;
if ((latitude == 0) || (longitude == 0))
LoadMap();
else
LoadMap(latitude, longitude, mapLoaded);
});
function mapLoaded() {
var title = "<%=Html.Encode(Model.Title) %>";
var address = "<%=Html.Encode(Model.Address) %>";
LoadPin(center, title, address);
map.SetZoomLevel(14);
}
</script>
Der erste <Skriptverweis> verweist auf die Microsoft Virtual Earth 6.2-Zuordnungsbibliothek. Der zweite <Skriptverweis> verweist auf eine map.js Datei, die wir in Kürze erstellen werden, die unsere allgemeine Javascript-Zuordnungslogik kapselt. Das <div id="theMap"> -Element ist der HTML-Container, den Virtual Earth zum Hosten der Karte verwendet.
Anschließend verfügen wir über einen eingebetteten <Skriptblock> , der zwei JavaScript-Funktionen enthält, die für diese Ansicht spezifisch sind. Die erste Funktion verwendet jQuery, um eine Funktion zu verknüpfen, die ausgeführt wird, wenn die Seite bereit ist, clientseitige Skripts auszuführen. Es ruft eine LoadMap()-Hilfsfunktion auf, die wir in unserer Map.js Skriptdatei definieren, um das Steuerelement für die virtuelle Erdkarte zu laden. Die zweite Funktion ist ein Rückrufereignishandler, der der Karte eine Anheftung hinzufügt, die einen Ort identifiziert.
Beachten Sie, dass wir einen serverseitigen <%= %> -Block innerhalb des clientseitigen Skriptblocks verwenden, um den Breiten- und Längengrad des Dinners einzubetten, den wir in JavaScript zuordnen möchten. Dies ist eine nützliche Technik, um dynamische Werte auszugeben, die von clientseitigen Skripts verwendet werden können (ohne dass ein separater AJAX-Rückruf an den Server erforderlich ist, um die Werte abzurufen, was ihn schneller macht). Die <%= %> -Blöcke werden ausgeführt, wenn die Ansicht auf dem Server gerendert wird– und daher wird die HTML-Ausgabe nur mit eingebetteten JavaScript-Werten enden (z. B. var latitude = 47,64312;).
Erstellen einer Map.js-Hilfsprogrammbibliothek
Nun erstellen wir die Map.js-Datei, die wir verwenden können, um die JavaScript-Funktionalität für unsere Zuordnung zu kapseln (und die oben genannten LoadMap- und LoadPin-Methoden zu implementieren). Klicken Sie dazu mit der rechten Maustaste auf das Verzeichnis \Scripts in unserem Projekt, wählen Sie dann den Menübefehl "Neues Element hinzufügen", wählen Sie das JScript-Element> aus, und nennen Sie es "Map.js".
Im Folgenden finden Sie den JavaScript-Code, den wir der Map.js-Datei hinzufügen, die mit Virtual Earth interagiert, um unsere Karte anzuzeigen und Ortsnadeln für unsere Abendessen hinzuzufügen:
var map = null;
var points = [];
var shapes = [];
var center = null;
function LoadMap(latitude, longitude, onMapLoaded) {
map = new VEMap('theMap');
options = new VEMapOptions();
options.EnableBirdseye = false;
// Makes the control bar less obtrusize.
map.SetDashboardSize(VEDashboardSize.Small);
if (onMapLoaded != null)
map.onLoadMap = onMapLoaded;
if (latitude != null && longitude != null) {
center = new VELatLong(latitude, longitude);
}
map.LoadMap(center, null, null, null, null, null, null, options);
}
function LoadPin(LL, name, description) {
var shape = new VEShape(VEShapeType.Pushpin, LL);
//Make a nice Pushpin shape with a title and description
shape.SetTitle("<span class=\"pinTitle\"> " + escape(name) + "</span>");
if (description !== undefined) {
shape.SetDescription("<p class=\"pinDetails\">" +
escape(description) + "</p>");
}
map.AddShape(shape);
points.push(LL);
shapes.push(shape);
}
function FindAddressOnMap(where) {
var numberOfResults = 20;
var setBestMapView = true;
var showResults = true;
map.Find("", where, null, null, null,
numberOfResults, showResults, true, true,
setBestMapView, callbackForLocation);
}
function callbackForLocation(layer, resultsArray, places,
hasMore, VEErrorMessage) {
clearMap();
if (places == null)
return;
//Make a pushpin for each place we find
$.each(places, function(i, item) {
description = "";
if (item.Description !== undefined) {
description = item.Description;
}
var LL = new VELatLong(item.LatLong.Latitude,
item.LatLong.Longitude);
LoadPin(LL, item.Name, description);
});
//Make sure all pushpins are visible
if (points.length > 1) {
map.SetMapView(points);
}
//If we've found exactly one place, that's our address.
if (points.length === 1) {
$("#Latitude").val(points[0].Latitude);
$("#Longitude").val(points[0].Longitude);
}
}
function clearMap() {
map.Clear();
points = [];
shapes = [];
}
Integrieren der Karte mit Formularen zum Erstellen und Bearbeiten
Wir integrieren nun die Kartenunterstützung in unsere vorhandenen Szenarien zum Erstellen und Bearbeiten. Die gute Nachricht ist, dass dies ziemlich einfach zu tun ist und dass wir keinen unserer Controller-Code ändern müssen. Da unsere Ansichten Erstellen und Bearbeiten eine gemeinsame Teilansicht "DinnerForm" verwenden, um die Benutzeroberfläche des Dinnerformulars zu implementieren, können wir die Karte an einem Ort hinzufügen und die Szenarien Erstellen und Bearbeiten verwenden.
Alles, was wir tun müssen, ist, die Teilansicht \Views\DinnerForm.ascx zu öffnen und zu aktualisieren, um unsere neue Teilkarte einzuschließen. Im Folgenden sehen Sie, wie das aktualisierte DinnerForm aussieht, sobald die Karte hinzugefügt wurde (Hinweis: Die HTML-Formularelemente werden aus Platzgründen aus dem folgenden Codeausschnitt weggelassen):
<%= Html.ValidationSummary() %>
<% using (Html.BeginForm()) { %>
<fieldset>
<div id="dinnerDiv">
<p>
[HTML Form Elements Removed for Brevity]
</p>
<p>
<input type="submit" value="Save"/>
</p>
</div>
<div id="mapDiv">
<%Html.RenderPartial("Map", Model.Dinner); %>
</div>
</fieldset>
<script type="text/javascript">
$(document).ready(function() {
$("#Address").blur(function(evt) {
$("#Latitude").val("");
$("#Longitude").val("");
var address = jQuery.trim($("#Address").val());
if (address.length < 1)
return;
FindAddressOnMap(address);
});
});
</script>
<% } %>
Die obige DinnerForm-Partielle akzeptiert ein Objekt vom Typ "DinnerFormViewModel" als Modelltyp (da sowohl ein Dinner-Objekt als auch ein SelectList-Objekt benötigt wird, um die Dropdownliste der Länder aufzufüllen). Unsere Karte benötigt nur ein Objekt vom Typ "Dinner" als Modelltyp, und wenn wir die Karte partielle rendern, übergeben wir nur die Dinner-Untereigenschaft von DinnerFormViewModel an sie:
<% Html.RenderPartial("Map", Model.Dinner); %>
Die JavaScript-Funktion, die wir teilweise hinzugefügt haben, verwendet jQuery, um ein "weichzeichnen"-Ereignis an das HTML-Textfeld "Address" anzufügen. Sie haben wahrscheinlich von "Fokus"-Ereignissen gehört, die ausgelöst werden, wenn ein Benutzer auf ein Textfeld klickt oder tabstoppt. Das Gegenteil ist ein "Weichzeichner"-Ereignis, das ausgelöst wird, wenn ein Benutzer ein Textfeld verlässt. Der obige Ereignishandler löscht die Breiten- und Längengrad-Textfeldwerte, wenn dies geschieht, und zeichnet dann den neuen Adressstandort auf unserer Karte. Ein Rückrufereignishandler, den wir in der map.js-Datei definiert haben, aktualisiert dann die Textfelder längen- und breitengrad in unserem Formular mithilfe von Werten, die von der virtuellen Erde basierend auf der angegebenen Adresse zurückgegeben werden.
Wenn wir jetzt unsere Anwendung erneut ausführen und auf die Registerkarte "Host Dinner" klicken, wird eine Standardkarte zusammen mit unseren Standard-Dinner-Formularelementen angezeigt:
Wenn wir eine Adresse eingeben und dann die Tabulatortaste entfernen, wird die Karte dynamisch aktualisiert, um den Standort anzuzeigen, und unser Ereignishandler füllt die Textfelder für Breiten-/Längengrad mit den Positionswerten auf:
Wenn wir das neue Abendessen speichern und es dann zur Bearbeitung erneut öffnen, wird der Kartenstandort angezeigt, wenn die Seite geladen wird:
Bei jeder Änderung des Adressfelds werden die Karte und die Breiten-/Längengradkoordinaten aktualisiert.
Jetzt, da die Karte den Speicherort des Abendessens anzeigt, können wir auch die Formularfelder Breiten- und Längengrad von sichtbaren Textfeldern ändern, um stattdessen ausgeblendete Elemente zu sein (da die Karte sie bei jeder Eingabe einer Adresse automatisch aktualisiert). Dazu wechseln wir von der Verwendung des HTML.TextBox()-HTML-Hilfsprogramm zur Verwendung der Html.Hidden()-Hilfsmethode:
<p>
<%= Html.Hidden("Latitude", Model.Dinner.Latitude)%>
<%= Html.Hidden("Longitude", Model.Dinner.Longitude)%>
</p>
Und jetzt sind unsere Formulare etwas benutzerfreundlicher und vermeiden es, den rohen Breiten-/Längengrad anzuzeigen (während sie immer noch mit jedem Dinner in der Datenbank gespeichert werden):
Integrieren der Karte in die Detailansicht
Nachdem wir nun die Karte in unsere Szenarien zum Erstellen und Bearbeiten integriert haben, integrieren wir sie auch in unser Detailszenario. Wir müssen lediglich %Html.RenderPartial("map"); %> in der Detailansicht aufrufen<.
Im Folgenden sehen Sie, wie der Quellcode für die vollständige Detailansicht (mit Kartenintegration) aussieht:
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent"runat="server">
<%= Html.Encode(Model.Title) %>
</asp:Content>
<asp:Content ID="details" ContentPlaceHolderID="MainContent" runat="server">
<div id="dinnerDiv">
<h2><%=Html.Encode(Model.Title) %></h2>
<p>
<strong>When:</strong>
<%=Model.EventDate.ToShortDateString() %>
<strong>@</strong>
<%=Model.EventDate.ToShortTimeString() %>
</p>
<p>
<strong>Where:</strong>
<%=Html.Encode(Model.Address) %>,
<%=Html.Encode(Model.Country) %>
</p>
<p>
<strong>Description:</strong>
<%=Html.Encode(Model.Description) %>
</p>
<p>
<strong>Organizer:</strong>
<%=Html.Encode(Model.HostedBy) %>
(<%=Html.Encode(Model.ContactPhone) %>)
</p>
<%Html.RenderPartial("RSVPStatus"); %>
<%Html.RenderPartial("EditAndDeleteLinks"); %>
</div>
<div id="mapDiv">
<%Html.RenderPartial("map"); %>
</div>
</asp:Content>
Wenn ein Benutzer nun zu einer /Dinners/Details/[id]-URL navigiert, sieht er Details zum Abendessen, zum Ort des Abendessens auf der Karte (mit einer Push-Pin, die beim Zeigen auf den Titel des Abendessens und die Adresse des Abendessens zeigt) und einen AJAX-Link zu RSVP dafür haben:
Implementieren der Standortsuche in unserer Datenbank und im Repository
Um unsere AJAX-Implementierung abzuschließen, fügen wir der Startseite der Anwendung eine Karte hinzu, die es Benutzern ermöglicht, grafisch nach Abendessen in ihrer Nähe zu suchen.
Wir beginnen mit der Implementierung der Unterstützung innerhalb unserer Datenbank- und Datenrepositoryebene, um effizient eine standortbasierte Radiussuche für Dinners durchzuführen. Wir könnten die neuen Geofeatures von SQL 2008 verwenden, um dies zu implementieren, oder alternativ können wir einen SQL-Funktionsansatz verwenden, den Gary Dryden hier im Artikel erläutert hat: http://www.codeproject.com/KB/cs/distancebetweenlocations.aspx.
Um dieses Verfahren zu implementieren, öffnen wir den "Server Explorer" in Visual Studio, wählen die NerdDinner-Datenbank aus, klicken dann mit der rechten Maustaste auf den Unterknoten "Functions" darunter, und wählen Sie aus, um eine neue "Skalarwertfunktion" zu erstellen:
Anschließend fügen wir die folgende DistanceBetween-Funktion ein:
CREATE FUNCTION [dbo].[DistanceBetween](@Lat1 as real,
@Long1 as real, @Lat2 as real, @Long2 as real)
RETURNS real
AS
BEGIN
DECLARE @dLat1InRad as float(53);
SET @dLat1InRad = @Lat1 * (PI()/180.0);
DECLARE @dLong1InRad as float(53);
SET @dLong1InRad = @Long1 * (PI()/180.0);
DECLARE @dLat2InRad as float(53);
SET @dLat2InRad = @Lat2 * (PI()/180.0);
DECLARE @dLong2InRad as float(53);
SET @dLong2InRad = @Long2 * (PI()/180.0);
DECLARE @dLongitude as float(53);
SET @dLongitude = @dLong2InRad - @dLong1InRad;
DECLARE @dLatitude as float(53);
SET @dLatitude = @dLat2InRad - @dLat1InRad;
/* Intermediate result a. */
DECLARE @a as float(53);
SET @a = SQUARE (SIN (@dLatitude / 2.0)) + COS (@dLat1InRad)
* COS (@dLat2InRad)
* SQUARE(SIN (@dLongitude / 2.0));
/* Intermediate result c (great circle distance in Radians). */
DECLARE @c as real;
SET @c = 2.0 * ATN2 (SQRT (@a), SQRT (1.0 - @a));
DECLARE @kEarthRadius as real;
/* SET kEarthRadius = 3956.0 miles */
SET @kEarthRadius = 6376.5; /* kms */
DECLARE @dDistance as real;
SET @dDistance = @kEarthRadius * @c;
return (@dDistance);
END
Anschließend erstellen wir in SQL Server eine neue Tabellenwertfunktion, die wir "NearestDinners" aufrufen:
Diese "NearestDinners"-Tabellenfunktion verwendet die DistanceBetween-Hilfsfunktion, um alle Dinner innerhalb von 100 Meilen von dem von uns bereitgestellten Breiten- und Längengrad zurückzugeben:
CREATE FUNCTION [dbo].[NearestDinners]
(
@lat real,
@long real
)
RETURNS TABLE
AS
RETURN
SELECT Dinners.DinnerID
FROM Dinners
WHERE dbo.DistanceBetween(@lat, @long, Latitude, Longitude) <100
Um diese Funktion aufzurufen, öffnen wir zunächst den LINQ to SQL Designer, indem wir auf die Datei NerdDinner.dbml in unserem Verzeichnis \Models doppelklicken:
Anschließend ziehen wir die Funktionen NearestDinners und DistanceBetween auf den LINQ to SQL-Designer, wodurch sie als Methoden unserer LINQ to SQL NerdDinnerDataContext-Klasse hinzugefügt werden:
Wir können dann eine "FindByLocation"-Abfragemethode für unsere DinnerRepository-Klasse verfügbar machen, die die NearestDinner-Funktion verwendet, um bevorstehende Dinner zurückzugeben, die sich innerhalb von 100 Meilen vom angegebenen Speicherort befinden:
public IQueryable<Dinner> FindByLocation(float latitude, float longitude) {
var dinners = from dinner in FindUpcomingDinners()
join i in db.NearestDinners(latitude, longitude)
on dinner.DinnerID equals i.DinnerID
select dinner;
return dinners;
}
Implementieren einer JSON-basierten AJAX-Suchaktionsmethode
Wir implementieren nun eine Controlleraktionsmethode, die die neue FindByLocation()-Repositorymethode nutzt, um eine Liste von Dinner-Daten zurückzugeben, die zum Auffüllen einer Zuordnung verwendet werden können. Diese Aktionsmethode gibt die Dinner-Daten in einem JSON-Format (JavaScript Object Notation) zurück, sodass sie problemlos mit JavaScript auf dem Client bearbeitet werden können.
Um dies zu implementieren, erstellen wir eine neue "SearchController"-Klasse, indem wir mit der rechten Maustaste auf das Verzeichnis \Controllers klicken und den Menübefehl Add-Controller> auswählen. Anschließend implementieren wir eine Aktionsmethode "SearchByLocation" in der neuen SearchController-Klasse wie folgt:
public class JsonDinner {
public int DinnerID { get; set; }
public string Title { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public string Description { get; set; }
public int RSVPCount { get; set; }
}
public class SearchController : Controller {
DinnerRepository dinnerRepository = new DinnerRepository();
//
// AJAX: /Search/SearchByLocation
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SearchByLocation(float longitude, float latitude) {
var dinners = dinnerRepository.FindByLocation(latitude,longitude);
var jsonDinners = from dinner in dinners
select new JsonDinner {
DinnerID = dinner.DinnerID,
Latitude = dinner.Latitude,
Longitude = dinner.Longitude,
Title = dinner.Title,
Description = dinner.Description,
RSVPCount = dinner.RSVPs.Count
};
return Json(jsonDinners.ToList());
}
}
Die SearchByLocation-Aktionsmethode des SearchController ruft intern die FindByLocation-Methode auf DinnerRepository auf, um eine Liste von Abendessen in der Nähe abzurufen. Anstatt die Dinner-Objekte jedoch direkt an den Client zurückzugeben, werden stattdessen JsonDinner-Objekte zurückgegeben. Die JsonDinner-Klasse macht eine Teilmenge der Dinner-Eigenschaften verfügbar (z. B. aus Sicherheitsgründen werden die Namen der Personen, die rsVP'd für ein Abendessen haben, nicht offengelegt). Sie enthält auch eine RSVPCount-Eigenschaft, die auf Dinner nicht vorhanden ist und die dynamisch berechnet wird, indem die Anzahl der RSVP-Objekte gezählt wird, die einem bestimmten Abendessen zugeordnet sind.
Anschließend verwenden wir die Json()-Hilfsmethode für die Controller-Basisklasse, um die Sequenz der Abendessen mithilfe eines JSON-basierten Wire-Formats zurückzugeben. JSON ist ein Standardtextformat für die Darstellung einfacher Datenstrukturen. Im Folgenden finden Sie ein Beispiel dafür, wie eine JSON-formatierte Liste von zwei JsonDinner-Objekten aussieht, wenn sie von unserer Aktionsmethode zurückgegeben wird:
[{"DinnerID":53,"Title":"Dinner with the Family","Latitude":47.64312,"Longitude":-122.130609,"Description":"Fun dinner","RSVPCount":2},
{"DinnerID":54,"Title":"Another Dinner","Latitude":47.632546,"Longitude":-122.21201,"Description":"Dinner with Friends","RSVPCount":3}]
Aufrufen der JSON-basierten AJAX-Methode mithilfe von jQuery
Wir sind jetzt bereit, die Startseite der NerdDinner-Anwendung so zu aktualisieren, dass die SearchByLocation-Aktionsmethode des SearchController verwendet wird. Dazu öffnen wir die Ansichtsvorlage /Views/Home/Index.aspx und aktualisieren sie so, dass sie über ein Textfeld, eine Suchschaltfläche, unsere Karte und ein <div-Element> namens dinnerList verfügt:
<h2>Find a Dinner</h2>
<div id="mapDivLeft">
<div id="searchBox">
Enter your location: <%=Html.TextBox("Location") %>
<input id="search" type="submit" value="Search"/>
</div>
<div id="theMap">
</div>
</div>
<div id="mapDivRight">
<div id="dinnerList"></div>
</div>
Anschließend können wir der Seite zwei JavaScript-Funktionen hinzufügen:
<script type="text/javascript">
$(document).ready(function() {
LoadMap();
});
$("#search").click(function(evt) {
var where = jQuery.trim($("#Location").val());
if (where.length < 1)
return;
FindDinnersGivenLocation(where);
});
</script>
Die erste JavaScript-Funktion lädt die Zuordnung, wenn die Seite zum ersten Mal geladen wird. Die zweite JavaScript-Funktion verkabelt einen JavaScript-Klickereignishandler auf der Suchschaltfläche. Wenn die Schaltfläche gedrückt wird, ruft sie die FindDinnersGivenLocation()-JavaScript-Funktion auf, die wir unserer Map.js-Datei hinzufügen:
function FindDinnersGivenLocation(where) {
map.Find("", where, null, null, null, null, null, false,
null, null, callbackUpdateMapDinners);
}
Diese FindDinnersGivenLocation()-Funktion ruft map auf. Suchen() auf der Virtual Earth Control, um es auf den eingegebenen Standort zu zentrieren. Wenn der Dienst für die virtuelle Erdkarte zurückgibt, wird die Karte zurückgegeben. Die Find()-Methode ruft die callbackUpdateMapDinners-Rückrufmethode auf, die wir als letztes Argument übergeben haben.
Die callbackUpdateMapDinners()-Methode ist der Ort, an dem die eigentliche Arbeit erledigt wird. Es verwendet die $.post()-Hilfsmethode von jQuery, um einen AJAX-Aufruf der SearchController SearchByLocation()-Aktionsmethode auszuführen und dabei den Breiten- und Längengrad der neu zentrierten Karte zu übergeben. Es definiert eine Inlinefunktion, die aufgerufen wird, wenn die $.post()-Hilfsmethode abgeschlossen ist, und die JSON-formatierten Dinnerergebnisse, die von der SearchByLocation()-Aktionsmethode zurückgegeben werden, werden mit einer Variablen namens "dinners" übergeben. Anschließend wird ein Foreach über jedes zurückgegebene Abendessen ausgeführt und der Breiten- und Längengrad des Abendessens sowie andere Eigenschaften verwendet, um der Karte eine neue Stecknadel hinzuzufügen. Außerdem wird der HTML-Liste der Abendessen rechts von der Karte ein Eintrag für das Abendessen hinzugefügt. Anschließend wird ein Hover-Ereignis sowohl für die Pins als auch für die HTML-Liste verkabelt, sodass Details zum Abendessen angezeigt werden, wenn ein Benutzer darauf zeigt:
function callbackUpdateMapDinners(layer, resultsArray, places, hasMore, VEErrorMessage) {
$("#dinnerList").empty();
clearMap();
var center = map.GetCenter();
$.post("/Search/SearchByLocation", { latitude: center.Latitude,
longitude: center.Longitude },
function(dinners) {
$.each(dinners, function(i, dinner) {
var LL = new VELatLong(dinner.Latitude,
dinner.Longitude, 0, null);
var RsvpMessage = "";
if (dinner.RSVPCount == 1)
RsvpMessage = "" + dinner.RSVPCount + "RSVP";
else
RsvpMessage = "" + dinner.RSVPCount + "RSVPs";
// Add Pin to Map
LoadPin(LL, '<a href="/Dinners/Details/' + dinner.DinnerID + '">'
+ dinner.Title + '</a>',
"<p>" + dinner.Description + "</p>" + RsvpMessage);
//Add a dinner to the <ul> dinnerList on the right
$('#dinnerList').append($('<li/>')
.attr("class", "dinnerItem")
.append($('<a/>').attr("href",
"/Dinners/Details/" + dinner.DinnerID)
.html(dinner.Title))
.append(" ("+RsvpMessage+")"));
});
// Adjust zoom to display all the pins we just added.
map.SetMapView(points);
// Display the event's pin-bubble on hover.
$(".dinnerItem").each(function(i, dinner) {
$(dinner).hover(
function() { map.ShowInfoBox(shapes[i]); },
function() { map.HideInfoBox(shapes[i]); }
);
});
}, "json");
Und wenn wir jetzt die Anwendung ausführen und die Startseite besuchen, wird uns eine Karte angezeigt. Wenn wir den Namen einer Stadt eingeben, werden auf der Karte die bevorstehenden Abendessen in der Nähe angezeigt:
Wenn Sie mit dem Mauszeiger auf ein Abendessen zeigen, werden Details dazu angezeigt.
Wenn Sie entweder in der Blase oder auf der rechten Seite in der HTML-Liste auf den Titel Dinner klicken, navigieren Sie zum Abendessen – für das wir dann optional RSVP verwenden können:
Nächster Schritt
Wir haben nun alle Anwendungsfunktionen unserer NerdDinner-Anwendung implementiert. Sehen wir uns nun an, wie wir automatisierte Komponententests dafür aktivieren können.