PDA

View Full Version : [CLOSED] Razor, X.Msg.Notify during a DirectEvent and ResourceManager



anup
May 11, 2012, 4:09 PM
Hi,

I am trying to create an MVC version of the example page that comes with the NuGet package.

The bit to create the window with the text area and button is straight forward enough:

View:



@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>DirectEventExample</title>
</head>
<body>
@Html.X().ResourceManager().Theme(Theme.Gray)

@(Html.X().Window()
.Title("Welcome to Ext.NET 2.0")
.Height(215)
.Width(350)
.BodyPadding(5)
.DefaultButton("0")
.Layout("AnchorLayout")
.DefaultAnchor("100%")
.Items(items => items.Add(Html.X()
.TextArea()
.EmptyText(">> Enter a Message Here <<")
.FieldLabel("Test Message")
.Height(85))
)
.Buttons(buttons => buttons.Add(Html.X()
.Button()
.Text("Submit")
.Icon(Icon.Accept)
.DirectEvents(directEvents => directEvents.Click.Url = "/DirectEventMessage/")
)
))
</body>
</html>


Controller:



public class DirectEventExampleController : Controller
{
//
// GET: /DirectEventExample/
public ActionResult Index()
{
return View();
}
}


That is all fine and it renders the same message box that your NuGet package installs by default.

But when I call the direct event, that is when I run into trouble; I can't seem to create the Notify on the server side. First I tried to create a simple strongly typed View which just registered the resource manager again and try to find a @Html.X().Msg or Notify or similar but couldn't see one. So then I tried to create a response script inside the controller action:



public class DirectEventMessageController : Controller
{
//
// GET: /DirectEventMessage/

public ActionResult Index(string message)
{
var config = new NotificationConfig
{
Icon = Icon.Accept,
Title = "Working",
Html = message
};

string script = X.Msg.Notify(config).ToScript();

return new AjaxResult(script);
}
}


If I run the above, I get a run time error saying

Object reference not set to an instance of an object

at Ext.Net.Notification.ToScript() +47

This is caused by my instance of Notification doing a .ToScript(); it is looking for a resource manager but can't find one, even if I have a View with just this:



@{
Layout = null;
}

@Html.X().ResourceManager()


Admittedly what I am trying feels wrong; I shouldn't be recreating another resource manager on the Direct Event click as there is already one on the page, but I guess I need to create a dummy/proxy one just so a script can be created and other server side code relying on it (to use things like RegisterIcon etc) will work... Trying to create it inside the Controller didn't work either (unless I didn't instantiate it properly)

Of course, I could get around this altogether by not making a Direct Event just to show the message the user typed and keeping it all on the client as it should be, but I am just trying to show the example that comes with NuGet as an MVC/Razor example. Also perhaps more realistically in the future I will want to create more complex layouts, grids, tabs, trees etc all on the fly using Direct Events or Direct Methods so it would still be useful to know where I am going wrong.

I am probably missing the obvious :)

Vladimir
May 11, 2012, 4:48 PM
Thank for the report
It was a bug in Notification code.

ResourceManager presence (or absence) in the view doesn't affect on controller action code. Action and View are not related between each other
Therefore ResourceManager is required for controls in the view only. If you create widgets in the controller action (dynamic controls without view) then resource manager will be created dynamically (when you call Render or ToScript)

By the way, AjaxResult can collect script automatically. You can call Show method for Notification and return AjaxResult
View


<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Ext.Net.MVC v2 Example</title>
</head>
<body>
<ext:ResourceManager ID="ResourceManager1" runat="server" />

<ext:Button runat="server" Text="Show notification">
<DirectEvents>
<Click Url="/Examples/Notification" />
</DirectEvents>
</ext:Button>


<ext:Label ID="Label1" runat="server" />
</body>
</html>



Action


public ActionResult Notification()
{
var config = new NotificationConfig
{
Icon = Icon.ApplicationStop,
Title = "Working",
Html = "Message"
};


X.Msg.Notify(config).Show();
X.GetCmp<Label>("Label1").Text = DateTime.Now.ToString();


return new AjaxResult();
}

anup
May 11, 2012, 5:54 PM
Many thanks for such a quick response and fix.

Just to clarify and check: does this look like best practice to you? I've put the Notify direct event handler as another action on the same controller (rather than creating a completely separate controller). More importantly, wanted to check the way I passed the message across was good practice (i.e. via the ExtraParam and setting the value by running some script to get values from something else on the page)?

View:



@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>DirectEventExample</title>
</head>
<body>
@Html.X().ResourceManager().Theme(Theme.Gray)

@(Html.X().Window()
.Title("Welcome to Ext.NET 2.0")
.Height(215)
.Width(350)
.BodyPadding(5)
.DefaultButton("0")
.Layout("AnchorLayout")
.DefaultAnchor("100%")
.Items(items => items.Add(Html.X()
.TextArea()
.ID("MessageTextArea")
.EmptyText(">> Enter a Message Here <<")
.FieldLabel("Test Message")
.Height(85))
)
.Buttons(buttons => buttons.Add(Html.X()
.Button()
.Text("Submit")
.Icon(Icon.Accept)
.DirectEvents(directEvents =>
{
directEvents.Click.Url = "/DirectEventExample/Notify";
directEvents.Click.ExtraParams.Add(new Parameter
{
Name = "message",
Value = "App.MessageTextArea.getValue()",
Mode = ParameterMode.Raw
});
})
)
))
</body>
</html>


Controller:



public class DirectEventExampleController : Controller
{
//
// GET: /DirectEventExample/
public ActionResult Index()
{
return View();
}

// GET: /DirectEventExample/Notify/
public ActionResult Notify(string message)
{
var config = new NotificationConfig
{
Icon = Icon.Accept,
Title = "Working",
Html = message
};

X.Msg.Notify(config).Show();

return new AjaxResult();
}
}


For more complex scenarios, e.g. passing more than one parameter, I'd have to add separate Extra Params parameters and for each one the value may be obtained by calling similar client side code, right?

Thanks!

Daniil
May 11, 2012, 7:21 PM
We are not sure that understand the questions well. But will try to answer.


Just to clarify and check: does this look like best practice to you? I've put the Notify direct event handler as another action on the same controller (rather than creating a completely separate controller).

It's hard to say definitely. I would not create a separate controller if it is not really required. Though separate controllers are helpful to separate logic. For example, I would define a separate controller to manage data of Stores.



Just to clarify and check: does this look like best practice to you? More importantly, wanted to check the way I passed the message across was good practice (i.e. via the ExtraParam and setting the value by running some script to get values from something else on the page)?

Well, I can't see any better way to pass parameter to a controller action in DirectEvent case. Can you see any?


For more complex scenarios, e.g. passing more than one parameter, I'd have to add separate Extra Params parameters and for each one the value may be obtained by calling similar client side code, right?

Yes, confirm.

Please note that DirectEvent can also automatically submit form values. It might be helpful in many scenarios. In this case you can set up FormCollection parameter for a controller action.

Also you can manage ExtraParams within DirectEvent Before and ResourceManager BeforeAjaxRequest handlers. There are two examples in this thread.
http://forums.ext.net/showthread.php?12972

anup
May 11, 2012, 7:34 PM
Thanks for your response.


It's hard to say definitely. I would not create a separate controller if it is not really required. Though separate controllers are helpful to separate logic. For example, I would define a separate controller to manage data of Stores.

Yes, that makes perfect sense. For stores in particular it creates excellent reuse and is easier to unit test etc too. In this particular example, it seems okay to keep it in the same controller as it is quite specific to this example page.


Well, I can't see any better way to pass parameter to a controller action in DirectEvent case. Can you see any?

Another way perhaps is not quite with a Direct Event but a client side click listener that would then call a direct event/direct method manually and just create the URL with appropriate querystings, perhaps. Seems more fiddly, but sometimes may be useful. (But then again, if we are creating the direct request manually, could still populate the extra params; probably cleaner!)



Please note that DirectEvent can also automatically submit form values. It might be helpful in many scenarios. In this case you can set up FormCollection parameter for a controller action.

Also you can manage ExtraParams within DirectEvent Before and ResourceManager BeforeAjaxRequest handlers. There are two examples in this thread.
http://forums.ext.net/showthread.php?12972

Thanks for the tip...!

Vladimir
May 11, 2012, 8:20 PM
You can use DirectMethod to call controller's action if you want to manage params on the fly


<Click Handler="Ext.net.DirectMethod.request({
url : '/Examples/Notification',
cleanRequest: true,
params : {
message : 'Message'
}
});" />


P.S. We will change DirectMethod/DirectRequest to automatically use 'cleanRequest' under MVC

anup
May 11, 2012, 9:17 PM
Thanks for that. I was thinking that is how it would probably be done; in fact, I do that for our production code; its incredibly powerful as we normally have to generate a lot of complex UI on the fly during various direct requests and quite often from Ext JS code. I was just thinking it might be a bit more fiddly for the very small example I was demonstrating here. But it is good to be in one thread here for future reference :)

Thanks for the tip on clean request too.