Wrox Programmer Forums

Need to download code?

View our list of code downloads.

Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read
BOOK: Professional ASP.NET MVC 2
This is the forum to discuss the Wrox book Professional ASP.NET MVC 2 by Jon Galloway, Scott Hanselman, Phil Haack, Scott Guthrie, Rob Conery; ISBN: Professional ASP.NET MVC 2
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: Professional ASP.NET MVC 2 section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developers’ questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
 
 
Thread Tools Display Modes
  #1 (permalink)  
Old September 14th, 2010, 05:55 AM
Registered User
 
Join Date: Sep 2010
Posts: 1
Thanks: 0
Thanked 0 Times in 0 Posts
Default Map Logic

I must have repeated this tutorial 4 times now and I cannot see what is going wrong.

Starting on Page 127 I have created the partial template and the Map.js file. However when I run it, I am getting an exception being thrown in the LoadMap() method of the Map.js file stating that "Microsoft JScript runtime error: 'NerdDinner' is undefined". Anyone know what could be up?

This is getting really frustrating now with the number of errors so early into the book.

TIA,
A.
  #2 (permalink)  
Old October 8th, 2010, 05:49 PM
Friend of Wrox
Points: 539, Level: 8
Points: 539, Level: 8 Points: 539, Level: 8 Points: 539, Level: 8
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Oct 2010
Location: Seattle
Posts: 106
Thanks: 1
Thanked 17 Times in 17 Posts
Default

Super frustrating for me too. It took me all afternoon to figure it out.

Code snippet 1-91.txt (for Map.js) appears to be incorrect. The following Map.js is what I got from a finished and working NerdDinner and inserted into my NerdDinner. The main difference I see is the NerdDinner prefix. Be aware there seems to be 3 different finished samples, the original one, MVC2 (the one in the book), and the ever changing one on Codeplex.

I discovered later on, it may not be a good idea to just copy-paste the Codeplex version (below) into your project. Some of the functions expect dinner to have more properties than what is shown in the book. In the event this doesnt work, it may be safer to just add the "NerdDinner" prefix to your existing Map.js instead of replacing the whole thing.

There may be a better way to fix this. But for now, this is it.

Code:
function NerdDinner() { }

NerdDinner.MapDivId = 'theMap';
NerdDinner._map = null;
NerdDinner._points = [];
NerdDinner._shapes = [];

NerdDinner.LoadMap = function (latitude, longitude, onMapLoaded) {
    NerdDinner._map = new VEMap(NerdDinner.MapDivId);

    var options = new VEMapOptions();

    options.EnableBirdseye = false

    // Makes the control bar less obtrusize.
    this._map.SetDashboardSize(VEDashboardSize.Small);

    if (onMapLoaded != null)
        NerdDinner._map.onLoadMap = onMapLoaded;

    if (latitude != null && longitude != null) {
        var center = new VELatLong(latitude, longitude);
    }

    NerdDinner._map.LoadMap(center, null, null, null, null, null, null, options);
}

NerdDinner.ClearMap = function () {
    NerdDinner._map.Clear();
    NerdDinner._points = [];
    NerdDinner._shapes = [];
}

NerdDinner.LoadPin = function (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>");
    }

    NerdDinner._map.AddShape(shape);
    NerdDinner._points.push(LL);
    NerdDinner._shapes.push(shape);
}

NerdDinner.FindAddressOnMap = function (where) {
    var numberOfResults = 1;
    var setBestMapView = true;
    var showResults = true;
    var defaultDisambiguation = true;

    NerdDinner._map.Find("", where, null, null, null,
                         numberOfResults, showResults, true, defaultDisambiguation,
                         setBestMapView, NerdDinner._callbackForLocation);
}

NerdDinner._callbackForLocation = function (layer, resultsArray, places, hasMore, VEErrorMessage) {
    NerdDinner.ClearMap();

    if (places == null) {
        NerdDinner._map.ShowMessage(VEErrorMessage);
        return;
    }

    //Make a pushpin for each place we find
    $.each(places, function (i, item) {
        var description = "";
        if (item.Description !== undefined) {
            description = item.Description;
        }
        var LL = new VELatLong(item.LatLong.Latitude,
                        item.LatLong.Longitude);

        NerdDinner.LoadPin(LL, item.Name, description);
    });

    //Make sure all pushpins are visible
    if (NerdDinner._points.length > 1) {
        NerdDinner._map.SetMapView(NerdDinner._points);
    }

    //If we've found exactly one place, that's our address.
    //lat/long precision was getting lost here with toLocaleString, changed to toString
    if (NerdDinner._points.length === 1) {
        $("#Latitude").val(NerdDinner._points[0].Latitude.toString());
        $("#Longitude").val(NerdDinner._points[0].Longitude.toString());
    }
}

NerdDinner.FindDinnersGivenLocation = function (where) {
    NerdDinner._map.Find("", where, null, null, null, null, null, false,
                         null, null, NerdDinner._callbackUpdateMapDinners);
}


NerdDinner.FindMostPopularDinners = function (limit) {
    $.post("/Search/GetMostPopularDinners", { "limit": limit }, NerdDinner._renderDinners, "json");
}

NerdDinner._callbackUpdateMapDinners = function (layer, resultsArray, places, hasMore, VEErrorMessage) {
    var center = NerdDinner._map.GetCenter();

    $.post("/Search/SearchByLocation",
           { latitude: center.Latitude, longitude: center.Longitude },
           NerdDinner._renderDinners,
           "json");
}


NerdDinner._renderDinners = function (dinners) {
    $("#dinnerList").empty();

    NerdDinner.ClearMap();

    $.each(dinners, function (i, dinner) {

        var LL = new VELatLong(dinner.Latitude, dinner.Longitude, 0, null);

        // Add Pin to Map
        NerdDinner.LoadPin(LL, _getDinnerLinkHTML(dinner), _getDinnerDescriptionHTML(dinner));

        //Add a dinner to the <ul> dinnerList on the right
        $('#dinnerList').append($('<li/>')
                        .attr("class", "dinnerItem")
                        .append(_getDinnerLinkHTML(dinner))
                        .append($('<br/>'))
                        .append(_getDinnerDate(dinner, "mmm d"))
                        .append(" with " + _getRSVPMessage(dinner.RSVPCount)));
    });

    // Adjust zoom to display all the pins we just added.
    if (NerdDinner._points.length > 1) {
        NerdDinner._map.SetMapView(NerdDinner._points);
    }

    // Display the event's pin-bubble on hover.
    $(".dinnerItem").each(function (i, dinner) {
        $(dinner).hover(
            function () { NerdDinner._map.ShowInfoBox(NerdDinner._shapes[i]); },
            function () { NerdDinner._map.HideInfoBox(NerdDinner._shapes[i]); }
        );
    });

    function _getDinnerDate(dinner, formatStr) {
        //return '<strong>' + _dateDeserialize(dinner.EventDate).format(formatStr) + '</strong>'; // Codeplex version
        return '<strong>' + _dateDeserialize(dinner.EventDate).toDateString() + '</strong>';
    }

    function _getDinnerLinkHTML(dinner) {
        //return '<a href="' + dinner.Url + '">' + dinner.Title + '</a>';   // Codeplex version has .Url.   The book does not do this.
        return '<a href="' + '/Dinners/Details/' + dinner.DinnerID + '">' + dinner.Title + '</a>';
    }

    function _getDinnerDescriptionHTML(dinner) {
        return '<p>' + _getDinnerDate(dinner, "mmmm d, yyyy") + '</p><p>' + dinner.Description + '</p>' + _getRSVPMessage(dinner.RSVPCount);
    }

    function _dateDeserialize(dateStr) {
        return eval('new' + dateStr.replace(/\//g, ' '));
    }


    function _getRSVPMessage(RSVPCount) {
        var rsvpMessage = "" + RSVPCount + " RSVP";

        if (RSVPCount > 1)
            rsvpMessage += "s";

        return rsvpMessage;
    }
}

NerdDinner.dragShape = null;
NerdDinner.dragPixel = null;

NerdDinner.EnableMapMouseClickCallback = function () {
    NerdDinner._map.AttachEvent("onmousedown", NerdDinner.onMouseDown);
    NerdDinner._map.AttachEvent("onmouseup", NerdDinner.onMouseUp);
    NerdDinner._map.AttachEvent("onmousemove", NerdDinner.onMouseMove);
}

NerdDinner.onMouseDown = function (e) {
    if (e.elementID != null) {
        NerdDinner.dragShape = NerdDinner._map.GetShapeByID(e.elementID);
        return true;
    }
}

NerdDinner.onMouseUp = function (e) {
    if (NerdDinner.dragShape != null) {
        var x = e.mapX;
        var y = e.mapY;
        NerdDinner.dragPixel = new VEPixel(x, y);
        var LatLong = NerdDinner._map.PixelToLatLong(NerdDinner.dragPixel);
        $("#Latitude").val(LatLong.Latitude.toString());
        $("#Longitude").val(LatLong.Longitude.toString());
        NerdDinner.dragShape = null;

        NerdDinner._map.FindLocations(LatLong, NerdDinner.getLocationResults);
    }
}

NerdDinner.onMouseMove = function (e) {
    if (NerdDinner.dragShape != null) {
        var x = e.mapX;
        var y = e.mapY;
        NerdDinner.dragPixel = new VEPixel(x, y);
        var LatLong = NerdDinner._map.PixelToLatLong(NerdDinner.dragPixel);
        NerdDinner.dragShape.SetPoints(LatLong);
        return true;
    }
}

NerdDinner.getLocationResults = function (locations) {
    if (locations) {
        var currentAddress = $("#Dinner_Address").val();
        if (locations[0].Name != currentAddress) {
            var answer = confirm("Bing Maps returned the address '" + locations[0].Name + "' for the pin location. Click 'OK' to use this address for the event, or 'Cancel' to use the current address of '" + currentAddress + "'");
            if (answer) {
                $("#Dinner_Address").val(locations[0].Name);
            }
        }
    }
}

Last edited by flyinhawaiian; October 13th, 2010 at 11:45 AM. Reason: Fixed _getDinnerLinkHTML(dinner) and _getDinnerDate methods in Map.js
  #3 (permalink)  
Old October 8th, 2010, 06:09 PM
Friend of Wrox
Points: 539, Level: 8
Points: 539, Level: 8 Points: 539, Level: 8 Points: 539, Level: 8
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Oct 2010
Location: Seattle
Posts: 106
Thanks: 1
Thanked 17 Times in 17 Posts
Default

Also, in DinnerForm.ascx, you'll get a runtime error because of this line:

FindAddressOnMap(address);

Change it to:
Code:
NerdDinner.FindAddressOnMap(address);
  #4 (permalink)  
Old October 10th, 2010, 12:46 PM
Registered User
 
Join Date: Oct 2010
Location: Zürich
Posts: 8
Thanks: 0
Thanked 1 Time in 1 Post
Default Map position totally wrong

Having run into the same issue, I've done as you suggest and although I now get the map showing up, it looks like the CSS is completely messed up.

I can see a grey box that looks like it's supposed to contain the map. However, this box isn't in the same part of the page as the books suggests it should be. Furthermore - and more importantly - the map isn't in this box. Instead, the map appears at the top-left of the page as if it's been absolutely-positioned. AND, the "Bing" logo is in the bottom-left of the screen (rather than the bottom-left of the map) and the legend is in the bottom-right.

It looks like the map isn't being contained within the "theMap" div.

http://screencast.com/t/Q9z1vDIg

Any ideas or suggestions? It's quite difficult to proceed through the rest of chapter while the map is blocking most of the controls on the page.
  #5 (permalink)  
Old October 11th, 2010, 11:59 AM
Friend of Wrox
Points: 539, Level: 8
Points: 539, Level: 8 Points: 539, Level: 8 Points: 539, Level: 8
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Oct 2010
Location: Seattle
Posts: 106
Thanks: 1
Thanked 17 Times in 17 Posts
Default

Mine isn't exactly showing up in the right place either. But a little closer. First, does your div tag have an id?
Code:
    <div id="mapDiv">
        <% Html.RenderPartial("map"); %>    
    </div>
2nd, does your site.css have the same id?
Code:
#mapDiv 
{
    float: right;
    width: 522px;
}
The Following User Says Thank You to flyinhawaiian For This Useful Post:
firedrawndagger (November 14th, 2010)
  #6 (permalink)  
Old October 11th, 2010, 01:11 PM
Registered User
 
Join Date: Oct 2010
Location: Zürich
Posts: 8
Thanks: 0
Thanked 1 Time in 1 Post
Default That's not the root of the problem

No, there's no CSS for #mapDiv anywhere in my solution.

In retrospect, this seems a little silly. However, while following the book, at no point have I been told to create a style for the mapDiv.

Also, even if there was a CSS selector for #mapDiv, this wouldn't explain why the map is 'blowing up' all over the page, i.e. the map in the top-left, "bing" in the bottom-left, and the map legend in the bottom-right of the webpage, entirely outside the div that's supposed to be containing it.

And why is the containing element (the visible grey box) below the controls rather than to the right of them? Yes, your CSS fix would probably resolve this, but shouldn't that be in the book?

I know you didn't write the book, flyinhawaiian, and I do appreciate your reply, but there's something other than positioning on the mapDiv going wrong here.

UPDATE: I've now added that styling, and the grey box (in which the map should be contained, has moved to the bottom-right. So it looks like there's supposed to be some styling attached to #dinnerDiv which hasn't been included in the book.

http://screencast.com/t/8VfQiedzO

flyinhawaiian - would I be right in thinking that you found that #mapDiv styling on a downloaded version of the project?

Last edited by ajameson; October 11th, 2010 at 01:19 PM.
The Following User Says Thank You to ajameson For This Useful Post:
firedrawndagger (November 14th, 2010)
  #7 (permalink)  
Old October 11th, 2010, 02:30 PM
Friend of Wrox
Points: 539, Level: 8
Points: 539, Level: 8 Points: 539, Level: 8 Points: 539, Level: 8
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Oct 2010
Location: Seattle
Posts: 106
Thanks: 1
Thanked 17 Times in 17 Posts
Default

What a major pain huh? You would think that the errata would be updated by now.

Yes, I probably got #mapDiv from another thread or the downloaded complete version. The completed version causes even more confusion because it's constantly changing...they put the map on the left instead of the right, things have been renamed.

I think we can download earlier versions of code. I'll take a look http://nerddinner.codeplex.com/Sourc...ist/changesets to see what I can find.

I'm also comparing my project side-by-side with the finished one to see what's different. That should reveal something.
  #8 (permalink)  
Old October 11th, 2010, 03:30 PM
Friend of Wrox
Points: 539, Level: 8
Points: 539, Level: 8 Points: 539, Level: 8 Points: 539, Level: 8
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Oct 2010
Location: Seattle
Posts: 106
Thanks: 1
Thanked 17 Times in 17 Posts
Default

Ok, finally I got mine fixed. I think there's two ways. Here's one way.
1. Kept the #mapDiv mentioned earlier (in Site.css)

2. Set the id in div tag for the map to "mapDiv"
Code:
        <div id="mapDiv">    
            <% Html.RenderPartial("Map", Model.Dinner); %>
        </div>
3. In Dinnerform.ascx, put the Html.RenderPartial at the top of the fieldset. Since the map is set to float right, everything afterwards will be rendered to the left of it.

4. At this point the Create and Edit should look correct since they both use Dinnerform.ascx.

5. Now fix Details.aspx in the same way, putting the render partial at the top. Open the form in designer. May need to adjust size of MainContent div. Why? There's less fields in the details page so it doesnt extend down as far as the Create/Edit pages. So the map will overlap the bottom of form. Notice they call it details page even though there's not a whole lot of details on that page?

The 2nd way: I havent tried this yet but should work better. Basically do the opposite of the above.

Create #dinnerDiv (instead of #mapDiv) in Site.css with float:left. Use this as the id for the div tags that enclose Dinner. Since dinner is float left, everything after it (the map) should render to the right. This means, the Html.RenderPartial("map") should be last, after all the dinner fields.
  #9 (permalink)  
Old October 11th, 2010, 04:18 PM
Registered User
 
Join Date: Oct 2010
Location: Zürich
Posts: 8
Thanks: 0
Thanked 1 Time in 1 Post
Default

Thanks for taking a close look, flyinhawaiian.

I've tried both your suggestions (moving RenderPartial to the top with the right-float, and at the bottom with dinnerDiv being left-floated) and while they do move the grey map container around (still not to the perfect location though) my big problem is that the map is still not rendering inside this container.

My entire Map.js file is as you posted up above in the second post. I think the important part is
Quote:
NerdDinner.MapDivId = 'theMap';
which matches with
Quote:
<div id="theMap"></div>
on the Map partial.

So the bigger puzzlement is why is the map not rendering inside its container? (I've checked it in Chrome, IE9 and FF.)
  #10 (permalink)  
Old October 11th, 2010, 05:10 PM
Friend of Wrox
Points: 539, Level: 8
Points: 539, Level: 8 Points: 539, Level: 8 Points: 539, Level: 8
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Oct 2010
Location: Seattle
Posts: 106
Thanks: 1
Thanked 17 Times in 17 Posts
Default

Add this to your Site.css When I took this out. I got the same warped out map as you did. So this has got to be it.

Site.css
Code:
#theMap
{
    position: relative; 
    width: 580px; 
    border: solid 1px #bbd1ec;
}

top of Map.ascx
Code:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NerdDinner.Models.Dinner>" %>
<script src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2" type="text/javascript"></script>

<div id="theMap" style="width:520px"></div>

Last edited by flyinhawaiian; October 11th, 2010 at 05:14 PM. Reason: Added use of theMap
The Following User Says Thank You to flyinhawaiian For This Useful Post:
 


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
How can I acheive this logic? OnDistantShores XSLT 3 February 26th, 2010 03:16 AM
Heat Map over Google Map ajit Javascript 0 March 7th, 2008 08:01 AM
And/Or Logic??? ninel SQL Server 2000 2 February 9th, 2007 10:33 AM
Mixing Data access logic and business logic polrtex BOOK: Professional Jakarta Struts 0 December 15th, 2003 06:19 PM



All times are GMT -4. The time now is 02:02 PM.


Powered by vBulletin®
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.