Korzystanie z technologii AJAX w celu implementacji scenariuszy mapowania
autor: Microsoft
Jest to krok 11 bezpłatnego samouczka aplikacji "NerdDinner" , który zawiera instrukcje tworzenia małej, ale kompletnej aplikacji internetowej przy użyciu ASP.NET MVC 1.
Krok 11 pokazuje, jak zintegrować obsługę mapowania AJAX z naszą aplikacją NerdDinner, umożliwiając użytkownikom, którzy tworzą, edytują lub wyświetlają kolacje, aby wyświetlić lokalizację kolacji graficznie.
Jeśli używasz ASP.NET MVC 3, zalecamy skorzystanie z samouczków Wprowadzenie With MVC 3 lub MVC Music Store.
NerdDinner — krok 11: integrowanie mapy AJAX
Teraz sprawimy, że nasza aplikacja będzie nieco bardziej ekscytująca wizualnie, integrując obsługę mapowania AJAX. Umożliwi to użytkownikom, którzy tworzą, edytują lub wyświetlają kolacje, aby wyświetlić lokalizację kolacji graficznie.
Tworzenie widoku częściowego mapy
Będziemy używać funkcji mapowania w kilku miejscach w naszej aplikacji. Aby zachować dry kodu, hermetyzujemy wspólną funkcjonalność mapy w ramach jednego szablonu częściowego, którego możemy ponownie używać w wielu akcjach i widokach kontrolera. Nadamy temu widokowi nazwę "map.ascx" i utworzymy go w katalogu \Views\Dinners.
Możemy utworzyć plik map.ascx częściowo, klikając prawym przyciskiem myszy katalog \Views\Dinners i wybierając polecenie menu Dodaj-Widok>. Nadamy widokowi nazwę "Map.ascx", sprawdzimy go jako widok częściowy i wskażemy, że przekażemy mu silnie typizację klasy modelu "Dinner":
Po kliknięciu przycisku "Dodaj" zostanie utworzony nasz szablon częściowy. Następnie zaktualizujemy plik Map.ascx, aby miał następującą zawartość:
<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>
Pierwsze <odwołanie do skryptu> wskazuje bibliotekę mapowania Microsoft Virtual Earth 6.2. Drugi <skrypt> odwołuje się do pliku map.js, który wkrótce utworzymy, który będzie hermetyzować naszą wspólną logikę mapowania języka JavaScript. Element <div id="theMap"> jest kontenerem HTML, który będzie używany przez Wirtualną Ziemię do hostowania mapy.
Następnie mamy osadzony <blok skryptu> , który zawiera dwie funkcje języka JavaScript specyficzne dla tego widoku. Pierwsza funkcja używa metody jQuery do podłączania funkcji, która jest wykonywana, gdy strona jest gotowa do uruchomienia skryptu po stronie klienta. Wywołuje ona funkcję pomocnika LoadMap(), którą zdefiniujemy w pliku skryptu Map.js w celu załadowania kontrolki mapy ziemi wirtualnej. Druga funkcja to procedura obsługi zdarzeń wywołania zwrotnego, która dodaje pinezkę do mapy, która identyfikuje lokalizację.
Zwróć uwagę, że używamy bloku %= %> po stronie serwera w bloku skryptu po stronie <klienta, aby osadzić szerokość geograficzną i długość geograficzną kolacji, którą chcemy zamapować w języku JavaScript. Jest to przydatna technika do wyprowadzania wartości dynamicznych, które mogą być używane przez skrypt po stronie klienta (bez konieczności oddzielnego wywołania AJAX z powrotem do serwera w celu pobrania wartości — co sprawia, że jest szybsze). <Bloki %= %> będą wykonywane, gdy widok jest renderowane na serwerze — dlatego dane wyjściowe kodu HTML będą po prostu zawierać osadzone wartości języka JavaScript (na przykład: var latitude = 47.64312;).
Tworzenie biblioteki narzędzi Map.js
Teraz utwórzmy plik Map.js, którego możemy użyć do hermetyzacji funkcji języka JavaScript dla naszej mapy (i zaimplementuj metody LoadMap i LoadPin powyżej). Możemy to zrobić, klikając prawym przyciskiem myszy katalog \Scripts w naszym projekcie, a następnie wybierając polecenie menu "Dodaj nowy> element", wybierz element JScript i nadaj mu nazwę "Map.js".
Poniżej znajduje się kod JavaScript, który dodamy do pliku Map.js, który będzie współdziałał z Wirtualną Ziemią, aby wyświetlić naszą mapę i dodać do niej pinezki dla naszych kolacji:
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 = [];
}
Integrowanie mapy z formularzami tworzenia i edytowania
Teraz zintegrujemy obsługę mapy z istniejącymi scenariuszami tworzenia i edytowania. Dobrą wiadomością jest to, że jest to dość łatwe do zrobienia i nie wymaga od nas zmiany żadnego kodu kontrolera. Ponieważ nasze widoki tworzenia i edytowania mają wspólny widok częściowy "DinnerForm" w celu zaimplementowania interfejsu użytkownika formularza kolacji, możemy dodać mapę w jednym miejscu i korzystać z niej zarówno w scenariuszach tworzenia, jak i edytowania.
Wszystko, co musimy zrobić, to otworzyć widok częściowy \Views\Dinners\DinnerForm.ascx i zaktualizować go, aby uwzględnić naszą nową mapę częściową. Poniżej przedstawiono wygląd zaktualizowanego formularza DinnerForm po dodaniu mapy (uwaga: elementy formularza HTML zostaną pominięte w poniższym fragmencie kodu w celu zwięzłości):
<%= 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>
<% } %>
Powyższy element DinnerForm przyjmuje obiekt typu "DinnerFormViewModel" jako typ modelu (ponieważ wymaga zarówno obiektu Dinner, jak i listy selectlist, aby wypełnić listę rozwijaną krajów). Nasza mapa częściowa potrzebuje obiektu typu "Dinner" jako typu modelu, a więc gdy renderujemy mapę częściową, przekazujemy tylko właściwość podrzędną DinnerFormViewModel do niego:
<% Html.RenderPartial("Map", Model.Dinner); %>
Funkcja Języka JavaScript dodawana do częściowej funkcji używa biblioteki jQuery w celu dołączenia zdarzenia "rozmycia" do pola tekstowego HTML "Address". Prawdopodobnie znasz zdarzenia "koncentracji uwagi", które są uruchamiane, gdy użytkownik kliknie lub karty w pole tekstowe. Przeciwieństwem jest zdarzenie "rozmycia", które jest uruchamiane, gdy użytkownik zamyka pole tekstowe. Powyższa procedura obsługi zdarzeń czyści wartości pól tekstowych szerokości i długości geograficznej, gdy tak się stanie, a następnie wykreśli nową lokalizację adresu na naszej mapie. Procedura obsługi zdarzeń wywołania zwrotnego zdefiniowana w pliku map.js zaktualizuje pola tekstowe długości i szerokości geograficznej w formularzu przy użyciu wartości zwróconych przez wirtualną ziemię na podstawie podanego adresu.
Teraz po ponownym uruchomieniu aplikacji i kliknięciu karty "Kolacja hosta" zostanie wyświetlona mapa domyślna wraz z naszymi standardowymi elementami formularza obiadu:
Po wpiseniu adresu, a następnie naciśnięciu klawisza Tab, mapa zostanie dynamicznie zaktualizowana, aby wyświetlić lokalizację, a nasz program obsługi zdarzeń wypełni pola tekstowe szerokości/długości geograficznej wartościami lokalizacji:
Jeśli zapiszemy nową kolację, a następnie otworzymy ją ponownie do edycji, zauważymy, że lokalizacja mapy jest wyświetlana po załadowaniu strony:
Za każdym razem, gdy pole adresu zostanie zmienione, mapa i współrzędne szerokości/długości geograficznej zostaną zaktualizowane.
Teraz, gdy mapa wyświetla lokalizację kolacji, możemy również zmienić pola formularza Szerokość geograficzna i Długość geograficzna z widocznych pól tekstowych, aby zamiast tego były elementami ukrytymi (ponieważ mapa jest automatycznie aktualizowana przy każdym wprowadzeniu adresu). Aby to zrobić, przełączymy się z używania pomocnika HTML.TextBox() do korzystania z metody pomocnika Html.Hidden():
<p>
<%= Html.Hidden("Latitude", Model.Dinner.Latitude)%>
<%= Html.Hidden("Longitude", Model.Dinner.Longitude)%>
</p>
A teraz nasze formularze są nieco bardziej przyjazne dla użytkownika i unikaj wyświetlania nieprzetworzonych szerokości/długości geograficznych (przy jednoczesnym przechowywaniu ich z każdą kolacją w bazie danych):
Integrowanie mapy z widokiem szczegółów
Teraz, gdy mapa jest zintegrowana z naszymi scenariuszami tworzenia i edytowania, zintegrujmy ją również z naszym scenariuszem Szczegóły. Wystarczy wywołać metodę <% Html.RenderPartial("map"); %> w widoku Szczegóły.
Poniżej znajduje się kod źródłowy pełnego widoku Szczegóły (z integracją mapy):
<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>
A teraz, gdy użytkownik przejdzie do adresu URL /Dinners/Details/[id], zobaczy szczegóły dotyczące kolacji, lokalizację kolacji na mapie (wraz z pinezką, która po umieszczeniu wskaźnika myszy na ekranie wyświetla tytuł kolacji i adres), a także link AJAX do RSVP dla niego:
Implementowanie wyszukiwania lokalizacji w naszej bazie danych i repozytorium
Aby zakończyć implementację AJAX, dodajmy mapę do strony głównej aplikacji, która umożliwia użytkownikom graficzne wyszukiwanie kolacji w pobliżu.
Zaczniemy od zaimplementowania obsługi w warstwie bazy danych i repozytorium danych w celu wydajnego przeprowadzania wyszukiwania promienia opartego na lokalizacji na potrzeby kolacji. Możemy użyć nowych funkcji geoprzestrzennych programu SQL 2008 , aby to zaimplementować, lub alternatywnie możemy użyć metody funkcji SQL, którą Gary Dryden omówił w artykule tutaj: http://www.codeproject.com/KB/cs/distancebetweenlocations.aspx.
Aby zaimplementować tę technikę, otworzymy "Eksplorator serwera" w programie Visual Studio, wybierz bazę danych NerdDinner, a następnie kliknij prawym przyciskiem myszy podwęźle "functions" i wybierz nową funkcję "Scalar-valued":
Następnie wklejymy następującą funkcję DistanceBetween:
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
Następnie utworzymy nową funkcję z wartością tabeli w SQL Server, którą wywołamy "NearestDinners":
Ta funkcja tabeli "NearestDinners" używa funkcji pomocnika DistanceBetween, aby zwrócić wszystkie kolacje w odległości 100 mil od szerokości geograficznej i długości geograficznej, do których ją podajemy:
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
Aby wywołać tę funkcję, najpierw otworzymy projektanta LINQ to SQL, klikając dwukrotnie plik NerdDinner.dbml w katalogu \Models:
Następnie przeciągniemy funkcje NearestDinners i DistanceBetween do projektanta LINQ to SQL, co spowoduje dodanie ich jako metod w klasie LINQ to SQL NerdDinnerDataContext:
Następnie możemy uwidocznić metodę zapytania "FindByLocation" w klasie DinnerRepository, która używa funkcji NearestDinner, aby zwrócić nadchodzące kolacje znajdujące się w odległości 100 mil od określonej lokalizacji:
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;
}
Implementowanie metody akcji wyszukiwania AJAX opartej na formacie JSON
Teraz zaimplementujemy metodę akcji kontrolera, która korzysta z nowej metody repozytorium FindByLocation(), aby zwrócić listę danych kolacji, których można użyć do wypełnienia mapy. Ta metoda akcji zwróci dane kolacji w formacie JSON (JavaScript Object Notation), aby można było łatwo manipulować przy użyciu języka JavaScript na kliencie.
Aby to zaimplementować, utworzymy nową klasę "SearchController", klikając prawym przyciskiem myszy katalog \Controllers i wybierając polecenie menu Dodaj kontroler>. Następnie zaimplementujemy metodę akcji "SearchByLocation" w nowej klasie SearchController, tak jak poniżej:
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());
}
}
Metoda akcji SearchByLocation elementu SearchController wewnętrznie wywołuje metodę FindByLocation w repozytorium DinnerRepository, aby uzyskać listę pobliskich kolacji. Zamiast zwracać obiekty Dinner bezpośrednio do klienta, zamiast tego zwraca obiekty JsonDinner. Klasa JsonDinner ujawnia podzbiór właściwości Dinner (na przykład: ze względów bezpieczeństwa nie ujawnia nazwisk osób, które mają RSVP'd na kolację). Zawiera również właściwość RSVPCount, która nie istnieje w kolacji i która jest obliczana dynamicznie przez zliczanie liczby obiektów RSVP skojarzonych z określoną kolacją.
Następnie używamy metody pomocnika Json() w klasie bazowej Kontroler, aby zwrócić sekwencję kolacji przy użyciu formatu przewodu opartego na formacie JSON. JSON to standardowy format tekstowy do reprezentowania prostych struktur danych. Poniżej przedstawiono przykładowy wygląd listy obiektów JsonDinner sformatowanych w formacie JSON:
[{"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}]
Wywoływanie metody AJAX opartej na formacie JSON przy użyciu metody jQuery
Teraz możemy zaktualizować stronę główną aplikacji NerdDinner, aby użyć metody akcji SearchByLocation searchController. W tym celu otworzymy szablon widoku /Views/Home/Index.aspx i zaktualizujemy go, aby mieć pole tekstowe, przycisk wyszukiwania, mapę i <element div> o nazwie dinnerList:
<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>
Następnie możemy dodać do strony dwie funkcje języka JavaScript:
<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>
Pierwsza funkcja języka JavaScript ładuje mapę po pierwszym załadowaniu strony. Druga funkcja JavaScript podłącza procedurę obsługi zdarzeń kliknięcia języka JavaScript na przycisku wyszukiwania. Po naciśnięciu przycisku wywołuje funkcję JavaScript FindDinnersGivenLocation(), którą dodamy do pliku Map.js:
function FindDinnersGivenLocation(where) {
map.Find("", where, null, null, null, null, null, false,
null, null, callbackUpdateMapDinners);
}
Ta funkcja FindDinnersGivenLocation() wywołuje mapę. Znajdź() w kontrolce Virtual Earth, aby wyśrodkować ją w wprowadzonej lokalizacji. Gdy zostanie zwrócona usługa mapy ziemi wirtualnej, mapa. Metoda Find() wywołuje metodę wywołania zwrotnego callbackUpdateMapDinners, która została przekazana jako ostatni argument.
Metoda callbackUpdateMapDinners() to miejsce, w którym wykonywana jest rzeczywista praca. Używa metody pomocniczej $.post() jQuery do wykonania wywołania AJAX do metody akcji SearchByLocation() SearchController — przekazując ją szerokość geograficzną i długość geograficzną nowo wyśrodkowanej mapy. Definiuje funkcję śródliniową, która zostanie wywołana po zakończeniu metody pomocnika $.post(), a wyniki kolacji sformatowane w formacie JSON zwrócone z metody akcji SearchByLocation() zostaną przekazane przy użyciu zmiennej o nazwie "kolacje". Następnie wykonuje foreach nad każdą zwróconą kolacją i używa szerokości geograficznej i długości geograficznej kolacji oraz innych właściwości, aby dodać nowy pin na mapie. Dodaje również wpis kolacji do listy HTML kolacji po prawej stronie mapy. Następnie przesunie zdarzenie aktywowania zarówno dla wypychań, jak i listy HTML, aby szczegóły dotyczące kolacji zostały wyświetlone, gdy użytkownik najecha kursorem na nich:
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");
A teraz, gdy uruchomimy aplikację i odwiedzimy stronę główną, zostanie wyświetlona mapa. Po wprowadzeniu nazwy miasta mapa wyświetli nadchodzące kolacje w pobliżu:
Zatrzymanie wskaźnika myszy na kolacji spowoduje wyświetlenie szczegółowych informacji o tym.
Kliknięcie tytułu kolacji w bąbelku lub po prawej stronie listy HTML spowoduje przejście do kolacji , którą możemy następnie opcjonalnie RSVP:
Następny krok
Teraz zaimplementowaliśmy wszystkie funkcje aplikacji naszej aplikacji NerdDinner. Przyjrzyjmy się teraz, jak możemy włączyć automatyczne testowanie jednostkowe.