Archive

Archive for the ‘jQuery’ Category

Bing Maps v6.3 – Context Menu with jQuery Plugin

September 29, 2010 Leave a comment

The tradition way to add a context menu for the Bing Map v6.3 is to attach event handler for “onclick” event and check if the right mouse button is clicked in the event handler. Please see Abhishek Sur‘s post for details.

There is another way to add a context menu – attach event handler for “oncontextmenu” event, but this is for Bing Map v4 (see this). The behavior is very similar to the “onclick” event in v6.3.

These two methods add some overhead in the event handling, and I found there are some glitches when handling “onclick” event – it’s better to check the right mouse button clicking in “onmouseup” event. Anyway, thanks to the jQuery Context Menu Plugin – it handles mouse and keyboard events very well and it makes adding context menus in Bing Map way easier.

Let’s check the source code of the demo page:

1 <%@ Page Language=”C#” AutoEventWireup=”true” CodeBehind=”ContextMenu.aspx.cs” Inherits=”BingMap.ContextMenu” %>

2

3 <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

4

5 <html xmlns=”http://www.w3.org/1999/xhtml&#8221; >

6 <head runat=”server”>

7 <title>Bing Map – Context Menu</title>

8 <script type=”text/javascript” src=”http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.3″></script>

9 <script src=”JavaScript/jquery-1.4.2.min.js” type=”text/javascript”></script>

10 <script src=”JavaScript/jquery.contextMenu.js” type=”text/javascript”></script>

11 <link href=”CSS/jquery.contextMenu.css” rel=”stylesheet” type=”text/css” />

12

13 <script type=”text/javascript”>

14 var map = null;

15

16 jQuery(document).ready(function() {

17 InitMap();

18 });

19

20 function InitMap() {

21 // Set and load map

22 map = new VEMap(“myMap”);

23 map.LoadMap(new VELatLong(49.260407, -123.114034), 15, VEMapStyle.Road);

24

25 // Add context menu to the map

26 jQuery(“#myMap”).contextMenu({

27 menu: ‘myMapContextMenu’

28 },

29 function(action, src, pos) {

30 MapContextMenuHandler(action, src, pos);

31 });

32

33 }

34

35 function MapContextMenuHandler(action, src, pos) {

36 if (action == “add_shape”) {

37 // Add a new shape

38 var pixel = new VEPixel(pos.x + 5, pos.y + 5);

39 var shape = new VEShape(VEShapeType.Pushpin, map.PixelToLatLong(pixel));

40 shape.SetCustomIcon(“<img src=’/images/POI_dd-via.png’ />”);

41 map.AddShape(shape);

42

43 // Add context menu to the map

44 var primitiveID = shape.Primitives[0].iid;

45 jQuery(“#” + primitiveID).contextMenu({

46 menu: ‘myShapeContextMenu’

47 },

48 function(action1, src1, pos1) {

49 ShapeContextMenuHandler(action1, src1, pos1);

50 });

51 }

52 }

53

54 function ShapeContextMenuHandler(action, src, pos) {

55 if (action == “remove_shape”) {

56 // Remove the shape

57 var primitiveID = jQuery(src).attr(“id”);

58 var shape = map.GetShapeByID(primitiveID);

59 if (shape != null) {

60 map.DeleteShape(shape);

61 }

62 }

63 }

64

65 </script>

66 </head>

67 <body>

68 <form id=”form1″ runat=”server”>

69 <div>

70 <div id=”myMap” style=”position: relative; width: 900px; height: 700px;“></div>

71

72 <ul id=”myMapContextMenu” class=”contextMenu”>

73 <li class=”edit”><a href=”#add_shape”>Add Shape</a></li>

74 <li class=”quit separator”><a href=”#quit”>Close</a></li>

75 </ul>

76

77 <ul id=”myShapeContextMenu” class=”contextMenu”>

78 <li class=”delete”><a href=”#remove_shape”>Remove Shape</a></li>

79 <li class=”quit separator”><a href=”#quit”>Close</a></li>

80 </ul>

81 </div>

82 </form>

83 </body>

84 </html>

The code is pretty self-explanatory. Here are some notes:

  1. Include jQuery and jQuery Context Menu Plugin JavaScripts and jQuery Context Menu CSS file.
  2. Two types of context menus:
    • myMapContextMenu – this context menu shows up when right mouse button is clicked anywhere inside the map – except the shapes (green dots). Selecting “Add Shape” will add a shape at the point right button was clicked.
    • myShapeContextMenu – this context menu shoes up when right mouse button is clicked on the shapes (green dots). Selecting “Remove shape” will remove the shape from the map.
  3. Use jQuery ready() to initialize map.
  4. Bind the myMapContextMenu to the map control and provide a callback named “MapContextMenuHandler”.
  5. In the callback “MapContextMenuHandler”, create a new shape with custom icon (green dot), then bind the myShapeContextMenu to the newly created shape and provide the callback named “ShapeContextMenuHanlder”. The import thing is I use “Primitive” of the shape as the hook to the shape itself – shape.Primitives[0].iid.
  6. In the callback “ShapeContextMenuHandler”, get back the primitive ID and find the shape with the primitive ID, then remove the shape from the map.

Cool, eh?

Here are screenshots:

  • Right-click shows up a context menu and select “Add Shape”.

  • A shape is added to the map.

  • Right-click the newly created shape to show the context menu. Click “Remove Shape” to remove this shape from the map.

Change Background Color of Invalid Controls with ASP.NET Validators

July 16, 2010 Leave a comment

Chris posted an excellent article explaining how to change background color of invalid controls (with ASP.NET Validators). In his article, the code loops through each validator in Page_Validators (it’s a global array in Javascript), finds the control to validate (ctrl.controltovalidate) of the validator, changes the background color of the control if the valiator is in invalid mode (ctrl.isvalid == false).

As the updates of validators only happens when the form is submitted, but I need a bit more – I want the updates trigger whenever the user makes change to the controls (type text in the text box, change option in the select box, etc).  Using bind() function in jQuery will do the trick.

Here is the code:

<script type=”text/javascript”>

var g_BackgroundColor = “#FFAAAA”;

jQuery(document).ready(function() {

for (var i = 0; i < Page_Validators.length; i++) {

var validator = Page_Validators[i];

if (validator.controltovalidate) {

BindValidatorsForChecking(validator.controltovalidate);

}

}

});

function OnUpdateValidators() {

for (var i = 0; i < Page_Validators.length; i++) {

var validator = Page_Validators[i];

// *** For each validator, find its associated control, then check its valid status

if (validator.controltovalidate) {

var control = document.getElementById(validator.controltovalidate);

if (control != null) {

control.style.backgroundColor = CheckValidatorsForControl(control) ? : g_BackgroundColor;

// *** Bind to check valid status

BindValidatorsForChecking(validator.controltovalidate);

}

}

}

}

// *** Check all validators for a control

function CheckValidatorsForControl(control) {

for (var i = 0; i < control.Validators.length; i++) {

if (!control.Validators[i].isvalid) {

return false;

}

}

return true;

}

// *** Bind to check valid status

function BindValidatorsForChecking(controlID) {

jQuery(“#” + controlID).bind(“blur focus mouseout mouseleave”, function(e) {

this.style.backgroundColor = CheckValidatorsForControl(this) ? : g_BackgroundColor;

});

}

</script>

In the code behind, you will need to hook the updates when the form is submitted as well:

Page.ClientScript.RegisterOnSubmitStatement(this.GetType(), “OnUpdateValidators_Key”, “OnUpdateValidators();”);

Categories: AJAX, ASP.NET, C#, jQuery Tags: , ,

jQuery and ASP.NET AJAX PageMethods

August 12, 2008 2 comments

In ASP.NET AJAX there are two ways to make AJAX calls to retrieve data from server side – Web Services and Page Methods. For the project I am working on, based on the design and flexibility for page developers, I use PageMethods to query data from the server side and it worked well. But there is one minor issue with PageMethods – you can’t assign Javascript inner functions for the success and error callbacks. It’s not a big deal, but I like the way that Google Map uses closures. So I searched for alternatives and I found jQuery has the ajax() function which is what I need.

Here I build two pages – one uses PageMethods, another used jQuery – for comparison of the syntax and usage.

I use two basic container classes for my data passed between client and server:

using System;

namespace Posts

{

[Serializable]

public class LatLong

{

public double? latitude;

public double? longitude;

}

}

using System;

namespace Posts

{

[Serializable]

public class MapView

{

public LatLong center;

public int? zoom;

}

}

The MapViewData class provides a static method to generate random map view data:

using System;

using System.Collections;

using System.Collections.Generic;

namespace Posts

{

public class MapViewData

{

public const double DefaultLatitude = 49.266214d;

public const double DefaultLongitude = -122.998577d;

public const int DefaultZoom = 12;

public static List<MapView> GenerateMapViewData(int count)

{

List<MapView> data = new List<MapView>();

Random rand = new Random();

for (int i = 0; i < count; i++)

{

double delta = rand.NextDouble() * 0.001d;

LatLong latlong = new LatLong();

latlong.latitude = DefaultLatitude + delta;

latlong.longitude = DefaultLongitude + delta;

MapView view = new MapView();

view.center = latlong;

view.zoom = DefaultZoom;

data.Add(view);

}

return (data);

}

}

}

The following static page method is in both ASP.NET AJAX and jQuery pages for return a collection of MapView objects to Javascript:

[WebMethod]

public static List<MapView> GetMapViewData(int count)

{

return (MapViewData.GenerateMapViewData(count));

}

The first example is the ASP.NET AJAX with PageMethods. Couple things to notice:

  1. EnablePageMethods=”true” in the ScriptManger – to enable the static page methods in ASP.NET page can be called from Javascript.
  2. In success_callback, the result is the collection of MapView objects. We can loop through the collection and access properties of each object.

<%@ Page Language=”C#” AutoEventWireup=”true” CodeBehind=”Compare1.aspx.cs” Inherits=”Posts.Compare1″ %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<html xmlns=”http://www.w3.org/1999/xhtml&#8221; >

<head runat=”server”>

<title>ASP.NET AJAX</title>

<script type=”text/javascript”>

function get_mapview_data(count)

{

PageMethods.GetMapViewData(

count,

success_callback,

error_callback

);

}

function success_callback(result, context, method)

{

var sb = new Sys.StringBuilder();

for (var i in result) {

sb.append(“center -> (“ + result[i].center.latitude + “, “ + result[i].center.longitude + “), “);

sb.append(“zoom -> “ + result[i].zoom);

sb.append(“<br/>”);

}

$get(“mapview_data”).innerHTML = sb.toString();

}

function error_callback(error, context, method)

{

$get(“mapview_data”).innerHTML = “Error –> “ + error.get_message();

}

</script>

</head>

<body>

<form id=”form1″ runat=”server”>

<asp:ScriptManager ID=”ScriptManager1″ runat=”server” EnablePageMethods=”true” />

<div>

<a href=”javascript:get_mapview_data(20);”>Get MapView data</a>

</div>

<br />

<div id=”mapview_data”></div>

</form>

</body>

</html>

The second example isjQuery with PageMethods. Couple things to notice too:

  1. The URL to request is the current page URL concatenated with “/PageMethodName”.
  2. I use JSON2 Javascript library to parse (deserialize) the XmlHttpRequest object returned in the error callback. You can use Sys.Serialization.JavaScriptSerializer.deserialize() to do the same thing here.
  3. There is no need to use ScriptManager.

<%@ Page Language=”C#” AutoEventWireup=”true” CodeBehind=”Compare2.aspx.cs” Inherits=”Posts.Compare2″ %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<html xmlns=”http://www.w3.org/1999/xhtml&#8221; >

<head runat=”server”>

<title>jQuery</title>

<script type=”text/javascript” src=”/JavaScript/jquery-1.2.6.min.js”></script>

<script type=”text/javascript” src=”/JavaScript/json2.js”></script>

<script type=”text/javascript”>

function get_mapview_data(count)

{

$.ajax({

type: “POST”,

url: window.location.href + “/GetMapViewData”,

data: “{\”count\”:\”" + count + “\”}”,

contentType: “application/json; charset=utf-8″,

dataType: “json”,

success: function(xhr, status) {

var sb = “”;

for (var i in xhr) {

sb += “center -> (“ + xhr[i].center.latitude + “, “ + xhr[i].center.longitude + “), “;

sb += “zoom -> “ + xhr[i].zoom;

sb += “<br/>”;

}

$(“#mapview_data”).html(sb);

},

error: function(xhr, status, error) {

var err = JSON.parse(xhr.responseText);

$(“#mapview_data”).html(“Error –> “ + err.Message);

}

});

}

</script>

</head>

<body>

<form id=”form1″ runat=”server”>

<div>

<a href=”javascript:get_mapview_data(20);”>Get MapView data</a>

</div>

<br />

<div id=”mapview_data”></div>

</form>

</body>

</html>

I use Firebug to check the Post and Response in both XmlHttpRequests, they are the same in both pages.

Follow

Get every new post delivered to your Inbox.