I was wondering if it is possible to make partialview with devexpress elements to work properly in Extjs panel. So far I managed to load partialview into Extjs panel.All devexpress controls are rendered in a proper way, however it seems that entire client side functinality of devexpress is gone - there is no reaction on hover, click etc. Here is my code
//loading partialView
Ext.getCmp('centerPanel').body.load({ url: 'Home/TempView',scripts:true})
//controller
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
public PartialViewResult TempView()
{
return PartialView();
}
}
//TempView
<div>
#Html.Partial("ToolBarView");
</div>
//ToolBarView
#using DevExpress.Web.Mvc.UI
#Html.DevExpress().ReportToolbar(settings => {
// The following settings are necessary for a Report Toolbar.
settings.Name = "ReportToolbar";
settings.ReportViewerName = "reportViewer1";
}).GetHtml()
Is there any way to make it work ?
Here is my application
http://www.sendspace.pl/file/591cd7a07e43f15a22759b2
With the ExtJS contentEl property you can include any content in a panel.
//index.cshtml
<div id="dxGrid">
#Html.Partial("GridViewPartialView")
</div>
//GridViewPartialView.cshtml
#Html.DevExpress().GridView(settings =>
{
settings.Name = "DevExGrid";
settings.CallbackRouteValues = new { Controller = "Home", Action = "GridViewPartialView" };
settings.Width = System.Web.UI.WebControls.Unit.Percentage(100);
settings.ClientSideEvents.EndCallback = "function(s, e) { endSizeGrid(s); }";
}).Bind(Model).GetHtml()
//ExtJS code
Ext.create('Ext.panel.Panel', {
contentEl: 'dxGrid',
id: 'gridContainer',
title: 'Devexpress inside ExtJS'
});
Keep in mind that if you resize the panel you need to resize the DevEx grid manually. You can achieve this by setting a listener on the panel with the DevEx control on it.
listeners: {
resize: function () {
adjustGridSize(this, DevExGrid);
}
}
When you interact with the DevEx control it will resize too, that is why you need to specify a clientsideevent called EndCallBack.
The implementation of the resize functions looks something like this:
function endSizeGrid(sender) {
var el = Ext.get("gridContainer");
adjustGridSize(el, sender);
};
function adjustGridSize(aGridPnl, aGridView) {
aGridView.SetHeight(aGridPnl.getHeight());
aGridView.SetWidth(aGridPnl.getWidth());
};
I hope this will help someone.
Related
I am trying to execute an action on a controller without redirecting to the associated view for that action. For a good example of what I am trying to achieve take a look at the music.xbox.com website. When you add a song to a selected playlist from a popup menu - the page just shows a notification without any redirect or refresh. how is this possible?
What I have is the following:
I have a _playlistPopupMenu partial view that renders the list of playlists as follows:
_PlaylistPopupMenu
#model List<OneMusic.Models.GetPlaylists_Result>
#if (Model.Count > 0)
{
<li style="height:2px" class="divider"></li>
foreach (var item in Model)
{
<li style="height:30px">#Html.DisplayFor(p => item.Name)
#Html.ActionLink(item.Name, "AddSong", "Playlist", new { playlistId = #item.PlaylistId, songId = 1 }, "")
</li>
}
}
The PlaylistController AddSong action is as follows:
public PartialViewResult AddSong(int? playlistId, int? songId)
{
if (ModelState.IsValid)
{
db.AddSongToPlaylist(playlistId, songId);
db.SaveChanges();
return PartialView("_AddToPlaylist", "");
}
return PartialView("_AddToPlaylist", "");
}
I am struggling with what to put in the _AddToPlaylist partial view which I think I need to be able to display a notification of some kind (Possiblly using PNotify add in for Bootstrap). MVC wants to always redirect to ../Playlist/AddSong?playlistId=1&songId=1
Any ideas on how to complete this last part of the problem would be great.
If you don't want "full page reloads" then you need to approach the problem slightly differently, using javascript to alter the page dynamically. A library such as JQuery might make manipulating the DOM a little easier.
Display the popup dynamically using javascript.
When the user hits OK/Submit on the popup, post the data back to the server using javascript, and have the controller you are posting to return some HTML.
Append the returned HTML block (partial view) to an existing div containing playlist tracks.
The most difficult part of this is the asynchronous post. Help with updating a div without reloading the whole page can be found in this question.
EDIT - Example
If you have a controller action (accepting POSTs) with the URL myapp.com/PlayList/AddSong/, then you'd set up JQuery to post to this URL. You'd also set up the data property with any form data which you'd like to post, in your case you'd add playistId and songId to the data property.
You'd then use the result of the AJAX query (HTML) and append it to the existing playlist HTML on the page. So assuming that you want to append the partial view's HTML to a div with ID playlistDiv, and assuming that your partial view returns HTML which is valid when appended to the existing playlist, then your javascript will look something like this:
var data = { playlistId: 1, songId: 1 };
$.ajax({
type: "POST",
url: 'http://myapp.com/PlayList/AddSong/',
data: data,
success: function(resultData) {
// take the result data and update the div
$("#playlistDiv").append(resultData.html)
},
dataType: dataType
});
Disclaimer: I can't guarantee that this code will work 100% (unless I write the program myself). There may be differences in the version of JQuery that you use, etc, but with a little tweaking it should achieve the desired result.
using System.Web.Mvc;
using System.Web.Mvc.Html;
public ActionResult Index()
{
HtmlHelper helper = new HtmlHelper(new ViewContext(ControllerContext, new WebFormView(ControllerContext, "Index"), new ViewDataDictionary(), new TempDataDictionary(), new System.IO.StringWriter()), new ViewPage());
helper.RenderAction("Index2");
return View();
}
public ActionResult Index2(/*your arg*/)
{
//your code
return new EmptyResult();
}
in your controller you must add bottom code:
public ActionResult Index(string msg)
{
if (Request.Url.ToString().Contains("yourNewExampleUrlWithOutRedirect.com"))
{
string html = "";
using (System.Net.WebClient client = new System.Net.WebClient())
{
client.Encoding = Encoding.UTF8;
html = client.DownloadString("https://NewExampleUrl.com/first/index?id=1");
}
Response.Write(html);
}
...
}
your view must be empty so you add bottom code
#{
ViewBag.Title = "sample title";
if (Request.Url.ToString().Contains("yourNewExampleUrlWithOutRedirect.com"))
{
Layout = null;
}else
{
Layout ="~/Views/Shared/_Layout.cshtml"
}
}
#if (Request.Url.ToString().Contains("yourNewExampleUrlWithOutRedirect.com")==false)
{
before view like :
<div>hello world</div>
}
I have a function that submits a form to a MVC controller as follows -
function submitForm() {
$.ajax
({
type: 'POST',
url: '/Users/Index',
data: $('#searchForm').serialize(),
beforeSend: function() {
$('.usersearchresult').fadeOut('fast', function () { $('.loadinggif').show(); });
},
success: function (response) {
$('.loadinggif').hide();
$('.usersearchresult').hide().html(response).fadeIn('normal');
},
error: function (response) {
alert(response);
$('.loadinggif').hide();
$('.usersearchresult').hide().html(response).fadeIn('normal');
}
});
return false;
}
I wanted a central location to catch errors so I have extended HandleErrorAttribute -
public class ClientExceptionAttribute : HandleErrorAttribute
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public override void OnException(ExceptionContext context)
{
Log.Error(context.Exception);
context.ExceptionHandled = true;
// Verify if AJAX request
if (context.HttpContext.Request.IsAjaxRequest())
{
// Use partial view in case of AJAX request
var result = new PartialViewResult();
result.ViewName = "~/views/shared/error.ascx";
context.Result = result;
}
}
}
The error view is very simple -
#model String
#{
Layout = null;
}
<div class="exception">
<img src="../Content/Graphics/warning.png" />
<br />
<div class="message">#(String.IsNullOrEmpty(Model) ? "User Entry Api is currently unavailable" : Model) </div>
</div>
The problem is that AJAX on error never renders the partial view (error.cshtml) - it just gives me a blank screen.
So I have two questions -
How do I make AJAX render the partial error view
How can I pass a model to a partial view in the ClientExceptionAttribute
Thank you!
result.ViewName = "~/views/shared/error.ascx"; should be result.ViewName = "Error";
If anyone knows the answer to question number two I'd appreciate it.
All , Say you have a code in a View like this.
<img src='#Url.Action("GetCaptchaImg")' alt='' />
and of course there is an Action named GetCaptchaImg in the controller which return a FileContentResult to View.
After open this view in FireFox. I found the Html code is
<img alt="" src="/Controllername/GetCaptchaImg" />
the src is not the real physical path . So My question is what is the real physical path of this img, How can I change the image by Ajax call to an Action? Hope you can help me . thanks.
You can make an ajax call to the actionresult and from that return the name of the image and onsuccess of your ajax call change the image
Alternatively you can do this thing, which i've implemented in my project
Make your HTML form like this
#using (Html.BeginForm("ActionResult", "Controller", FormMethod.Post, new { #id = "ImgForm", #enctype = "multipart/form-data", name = "ImgForm", target = "UploadTarget" }))
{
}
Make an iframe as target of your form
<iframe id="UploadTarget" name="UploadTarget" onload="UploadImage_Complete();" style="position: absolute;
left: -999em; top: -999em;"></iframe>
Your upload control
Then upload the Image and Show it on your form
function UploadImage() {
$("#ImgForm").submit(); //form id
}
function UploadImage_Complete() {
try {
//Check to see if this is the first load of the iFrame
if (isFirstLoad == true) {
isFirstLoad = false;
return;
}
//Reset the image form so the file won't get uploaded again
document.getElementById("ImgForm").reset();
//Grab the content of the textarea we named jsonResult . This shold be loaded into
//the hidden iFrame.
var newImg = $.parseJSON($("#UploadTarget").contents().find("#jsonResult")[0].innerHTML);
if (newImg.IsValid) {
document.getElementById("dp").src = newImg.ImagePath;
document.getElementById('profile-pic').src = newImg.ThumbnailPath;
document.getElementById("change").style.display = "block";
}
// If there was an error, display it to the user
if (newImg.IsValid == false) {
alert(newImg.Message);
return;
}
}
catch (e) {
}
}
Your Action will look like this
public WrappedJsonResult ChangeImage(HttpPostedFileBase file)
{
}
and your WrappedJsonResult class will look likes
public class WrappedJsonResult : JsonResult
{
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Write("<html><body><textarea id=\"jsonResult\" name=\"jsonResult\">");
base.ExecuteResult(context);
context.HttpContext.Response.Write("</textarea></body></html>");
context.HttpContext.Response.ContentType = "text/html";
}
}
When I try and upload a file using ASP.NET MVC it works fine in FF && Chrome, but in IE and Opera a dialog pops-up which asks me to either download, save or cancel.
Choosing either of the options, prevents the fileupload from working. How can I get round this problem?
public class ImportModel
{
[Required]
[FileExtensions("csv", ErrorMessage = "Please upload a valid .csv file")]
public HttpPostedFileBase File { get; set; }
}
[HttpPost]
public virtual ActionResult StartImport(ImportModel model = null)
{
if (model != null)
{
var status = _importService.StartImport(model);
return Json(status, JsonRequestBehavior.AllowGet);
}
return null;
}
View code below (summarised):
<div id="dlgImport" class="hidden">
#using (Html.BeginForm(MVC.Import.StartImport(), FormMethod.Post, new { #class = "smallForm", id = "frmImport", enctype = "multipart/form-data" }))
{
<div class="fields-inline">
<div class="editor-label">
#Html.Label("File")
</div>
<div class="editor-field">
#Html.TextBoxFor(x => x.File, new { #class="input-file", type = "file" })
#Html.ValidationMessageFor(x => x.File)
</div>
</div>
}
</div>
</div>
$(function() {
$("#frmImport").ajaxForm({
success: function (responseHtml) {
// response is wrapped in pre tags by the browser - the ajax upload is carried out using an iframe
var response = $.parseJSON($(responseHtml).text());
}
});
});
var vm = {
startImport: function () {
if ($("#frmImport").valid()) {
$("#frmImport").submit();
}
}
}
Now that you have posted your code it looks like that you are using the jquery form plugin. As explained in the documentation this plugin supports file uploads using AJAX but you cannot return JSON from your server side script:
Since it is not possible to upload files using the browser's
XMLHttpRequest object, the Form Plugin uses a hidden iframe element to
help with the task. This is a common technique, but it has inherent
limitations. The iframe element is used as the target of the form's
submit operation which means that the server response is written to
the iframe. This is fine if the response type is HTML or XML, but
doesn't work as well if the response type is script or JSON, both of
which often contain characters that need to be repesented using entity
references when found in HTML markup.
To account for the challenges of script and JSON responses, the Form
Plugin allows these responses to be embedded in a textarea element and
it is recommended that you do so for these response types when used in
conjuction with file uploads. Please note, however, that if there is
no file input in the form then the request uses normal XHR to submit
the form (not an iframe). This puts the burden on your server code to
know when to use a textarea and when not to.
So basically your upload controller action should respond with:
<textarea>{"foo":"bar"}</textarea>
instead of:
{"foo":"bar"}
Also you should not use the application/json response content type in this case.
You could write a custom action result to achieve that:
public class FileJsonResult : JsonResult
{
public FileJsonResult(object data)
: base()
{
Data = data;
JsonRequestBehavior = JsonRequestBehavior.AllowGet;
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Write("<textarea>");
base.ExecuteResult(context);
context.HttpContext.Response.Write("</textarea>");
context.HttpContext.Response.ContentType = "text/html";
}
}
and then:
[HttpPost]
public virtual ActionResult StartImport(ImportModel model = null)
{
if (model != null)
{
var status = _importService.StartImport(model);
return new FileJsonResult(status);
}
new FileJsonResult(new { status = false, errorMessage = "The model was null" });
}
Now you might also need to adapt your success handler to strip the <textarea> tags:
$('#frmImport').ajaxForm({
success: function (responseHtml) {
var responseHtml = responseHtml
.replace(/\<textarea\>/i, '')
.replace(/\<\/textarea\>/i, '');
var response = $.parseJSON(responseHtml);
// do something with the response
}
});
I had the same problem with IE8 and this answer helped me a lot. But I needed to make some changes that worked very well in IE8, Chrome and Firefox.
Follow changes below:
success: function (responseText) {
try{
var response = $.parseJSON(responseText);
//code ...
}
catch(ex) {
//error code
}
}
[HttpPost]
public JsonResult Upload(HttpPostedFileBase file) {
//code
return Json(new { Success = "true", Message = "Done!" }, "text/html");
}
I have a ASP.Net MVC JsonResult function in which I want to return the contents of a PartialView (The content has to be loaded using Ajax, and for some reason I can't return a PartialViewResult).
To render the PartialView I need the ViewContext object.
How do you get the current ViewContext object within an Action method? I don't even see HttpContext.Current in my action method.
I am using ASP.net MVC 1.
a ViewContext is not available within the action method because it is constructed later before rendering the view. I would suggest you using MVCContrib's BlockRenderer to render the contents of a partial view into a string.
I may have missed a point somewhere but my Actions that returned partial views do so by returning a View object that refers to an ascx page. This will return partial HTML without the full page constructs (html, head, body, etc.). Not sure why you'd want to do anything beyond that, is there a specific reason you need to return PartialViewResult? Here's an example from my working code.
First the Action in my controller:
public ViewResult GetPrincipleList(string id)
{
if (id.Length > 1)
id = id.Substring(0, 1);
var Principles = competitorRepository.Principles.Where(p => p.NaturalKey.StartsWith(id)).Select(p=>p);
return View(Principles);
}
And then the partial view (ascx):
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<MyProject.Data.Principle>>" %>
<% foreach (var item in Model) { %>
<div class="principleTitle" title="<%= Html.Encode(item.NaturalKey) %>"><%= Html.Encode(item.Title) %></div>
<%} %>
Lastly, the Jquery that sets up the call:
$(function() {
$(".letterSelector").click(function() {
$("#principleList").load("/GetPrincipleList/" + $(this).attr("title"), null, setListClicks);
});
});
So, a full AJAX process, hope that helps.
---- UPDATE following comment ----
Returning Json data is just as easy:
Firstly, initiating the AJAX call when a select box changes:
$("#users").change(function() {
var url = "/Series/GetUserInfo/" + $("#users option:selected").attr("value");
$.post(url, null, function(data) { UpdateDisplay(data); }, 'json');
});
The javascript that processes the returned json data:
function UpdateDisplay(data) {
if (data != null) {
$("div.Message").fadeOut("slow", function() { $("div.Message").remove(); });
$("#Firstname").val(data.Firstname);
$("#Lastname").val(data.Lastname);
$("#List").val(data.List);
$("#Biography").val(data.Biography);
if (data.ImageID == null) {
$("#Photo").attr({ src: "/Content/Images/nophoto.png" });
$("#ImageID").val("");
}
else {
if (data.Image.OnDisk) {
$("#Photo").attr({ src: data.Image.ImagePath });
}
else {
$("#Photo").attr({ src: "/Series/GetImage?ImageID=" + data.ImageID });
}
$("#ImageID").val(data.ImageID);
}
$("form[action*='UpdateUser']").show();
} else {
$("form[action*='UpdateUser']").hide();
}
};
And finally the Action itself that returns the json data:
public JsonResult GetUserInfo(Guid id)
{
MyUser myuser = (from u in seriesRepository.Users
where u.LoginID == id
select u).FirstOrDefault();
if (myuser == null)
{
myuser = new MyUser();
myuser.UserID = 0;
myuser.Firstname = Membership.GetUser(id).UserName;
myuser.Lastname = "";
myuser.List = "";
myuser.Biography = "No yet completed";
myuser.LoginID = id;
}
return Json(myuser);
}
Does that help? If not then can you post some of the code you are working on as I'm missing something.