Data model is not getting deserialised in controller - javascript

Here is my model class
public class ProductModel
{
public Product {set;set;} // Product is one more class
}
I am using below javascript code to get partial view but 'model' is not getting deserialised in controller...What I am missing?
Storing data in a HTML attribute as shown below
JavaScriptSerializer serializer = new JavaScriptSerializer();
var jsonObject = serializer.Serialize(obj)
<span data-singleproduct="#jsonObject" id="#mprodid" class="ShowProductModal">Find out more..</span>
Used jQuery to call partial page and popup
$('.ShowProductModal').on('click', function () {
var model = $(this).data('singleproduct');
//I can see data of variable model here in developer tool
$("#ProductModal").dialog({
autoOpen: true,
position: { my: "center", at: "top+350", of: window },
width: 1000,
resizable: false,
title: '',
modal: true,
open: function () {
$(this).load('ShowProductModal', model );
},
buttons: {
}
});
return false;
});
Here is my controller code
public PartialViewResult ShowProductModal(ProductModel product)
{
return PartialView("ProductModal", product);
}
product always comes as null!!!
If I change ProductModel to Product , then it will work... ! CAN SOMEONE HELP ME?
public PartialViewResult ShowProductModal(Product product)
{
return PartialView("ProductModal", product);
}

You should try
$(this).load('ShowProductModal', { product: model });
And declare your method like this:
[HttpPost]
public PartialViewResult ShowProductModal([FromBody] JObject data)
{
var product = data["product"].ToObject<ProductModel>();
return PartialView("_SC5ProductModal", product);
}

Related

Ajax Error on Loading Datatable

I am currently trying to load a data table from my controller, and this Ajax Error appears
enter image description here
function InitOverviewDataTable() {
$("#data-table").dataTable().fnDestroy();
$('#data-table').dataTable({
bProcessing: true,
sAjaxSource: '#Url.Action("LoadUser", "Setup")'
});
}
[HttpPost]
public ActionResult LoadUser()
{
var users = db.R_User.ToList()
.Select(a => new
{
employee_number = a.employee_number,
role_id = a.role_id,
active_status = a.active_status
});
return Json(users);
}
Thanks in Advance.

TypeScript nesting static properties

I'm trying to build a class that will contain constant values to be used at different places.
The structure should be something like this:
class JavascriptEvents {
static change: string = "change";
static click: string = "click";
static blur: string = "blur";
static inputChange: string = "input propertychange paste";
static dblClick: string = "dblclick";
static bootstrap: Object = {
accordion: {
show: "show.bs.collapse",
shown: "shown.bs.collapse",
hide: "hide.bs.collapse",
hidden: "hidden.bs.collapse"
},
modal: {
shown: "shown.bs.modal",
show: "show.bs.modal",
hide: "hide.bs.modal",
hidden: "hidden.bs.modal",
loaded: "loaded.bs.modal"
}
}
}
Question: How should the bootstrap part be nested so I can reference an event like:
$("someElement").on(JavascriptEvents.bootstrap.modal.shown, function(){
// do whatever needed
});
I think the problem is the : Object declaration, which hid all the type information from the call site. If you simply remove it, the type checker should be happy again.
E.g.:
class JavascriptEvents {
static bootstrap: Object = {
modal: {
shown: "shown.bs.modal",
}
}
static bootstrap2 = {
modal: {
shown: "shown.bs.modal",
}
}
}
let jq: any;
jq.on(JavascriptEvents.bootstrap.modal.shown); // Error
jq.on(JavascriptEvents.bootstrap2.modal.shown); // Works
Playground

Kendo: How do I create a recursive hieiarchy in the TreeView?

I am using Kendo UI and trying to figure out how to get the TreeView to display a recursive hierarchy. Firstly, here is my model (I am retrieving a list of these objects by OData):
public class PageTreeItem
{
public Guid Id { get; set; }
public string Name { get; set; }
public bool IsEnabled { get; set; }
public PageTreeItem[] SubPages { get; set; }
}
And here is my JavaScript:
var PagesDS = new kendo.data.HierarchicalDataSource({
type: "odata",
transport: {
read: {
url: "/odata/cms/PageTree",
dataType: "json"
}
},
schema: {
data: function (response) {
return response.value;
},
total: function (response) {
return response.value.length;
},
model: {
id: "Id",
children: "SubPages"
}
}
});
PagesDS.read();
$("#treeview").kendoTreeView({
template: kendo.template($("#treeview-template").html()),
dataSource: PagesDS,
dataTextField: ["Name"]
});
And finally, the markup:
<div id="treeview"></div>
<script id="treeview-template" type="text/kendo-ui-template">
#= item.Name #
</script>
I can only ever get the top-level items to display. Obviously, setting the "children" property in schema-> model is not working. How do I achieve what I want?
OK, ignore.. my problem was with the SubPages not actually being returned in the first place... oops! I simply assumed they were automatically serialized with everything else. I needed to provide the $expand option in my OData query, as follows:
read: {
url: "/odata/cms/PageTree?$expand=SubPages",
dataType: "json"
}

HTTP handlers and javascript bundling in VS 2012

I am currently trying to setup a project to implement localization on javascript files (as described here) but at the same time I'd like to bundle and minify the javascript in the project. I followed a tutorial on bundling and minification here
I have been able to get both working separately, but when I try to get them working together I cannot get the localisation working properly. I think this is because bundling creates it's own route handling for the bundled/minified javascript it generates, so the httpHandler I have defined in the webconfig gets ignored. I keep getting javascript errors saying "CustomTranslate is not defined".
I am trying to do this because we are building a number of controls using ExtJS, but we need to be able to apply localisation to those controls. Any help/ideas on how I can get them to work together would be appreciated.
I am not using MVC, but doing this in asp.net in Visual Studio 2012.
Here is my code:
BundleConfig.cs
namespace TranslationTest
{
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
//default bundles addeed here...
bundles.Add(new ScriptBundle("~/bundles/ExtJS.axd").Include("~/Scripts/ExtJS/ext-all.js", "~/Scripts/ExtJS/TestForm.js"));
}
}
}
web.config:
<globalization uiCulture="auto" />
<httpHandlers>
<add verb="*" path="/bundles/ExtJS.axd" type="TranslationTest.ScriptTranslator, TranslationTest" />
</httpHandlers>
Default.aspx
<%# Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TranslationTest._Default" %>
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
<script src="/bundles/ExtJS.axd"></script>
</asp:Content>
TestForm.js:
Ext.require([
'Ext.form.*',
'Ext.layout.container.Column',
'Ext.tab.Panel'
]);
Ext.onReady(function () {
Ext.QuickTips.init();
var bd = Ext.getBody();
bd.createChild({ tag: 'h2', html: 'Form 1' });
var simple = Ext.create('Ext.form.Panel', {
url: 'save-form.php',
frame: true,
title: 'Simple Form',
bodyStyle: 'padding:5px 5px 0',
width: 350,
fieldDefaults: {
msgTarget: 'side',
labelWidth: 75
},
defaultType: 'textfield',
defaults: {
anchor: '100%'
},
items: [{
fieldLabel: CustomTranslate(FirstName),
name: 'first',
allowBlank: false
}, {
fieldLabel: CustomTranslate(LastName),
name: 'last'
}, {
fieldLabel: CustomTranslate(Company),
name: 'company'
}, {
fieldLabel: CustomTranslate(Email),
name: 'email',
vtype: 'email'
}, {
xtype: 'timefield',
fieldLabel: CustomTranslate(Time),
name: 'time',
minValue: '8:00am',
maxValue: '6:00pm'
}],
buttons: [{
text: CustomTranslate(Save)
}, {
text: CustomTranslate(Cancel)
}]
});
simple.render(document.body);
});
Currently the FirstName, LastName, etc are all stored in resource files, as in the linked example above.
ScriptTranslator.cs
namespace TranslationTest
{
public class ScriptTranslator : IHttpHandler
{
#region IHttpHandler Members
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
string relativePath = context.Request.AppRelativeCurrentExecutionFilePath.Replace(".axd", string.Empty);
string absolutePath = context.Server.MapPath(relativePath);
string script = ReadFile(absolutePath);
string translated = TranslateScript(script);
context.Response.Write(translated);
Compress(context);
SetHeadersAndCache(absolutePath, context);
}
#endregion
private void SetHeadersAndCache(string file, HttpContext context)
{
context.Response.AddFileDependency(file);
context.Response.Cache.VaryByHeaders["Accept-Language"] = true;
context.Response.Cache.VaryByHeaders["Accept-Encoding"] = true;
context.Response.Cache.SetLastModifiedFromFileDependencies();
context.Response.Cache.SetExpires(DateTime.Now.AddDays(7));
context.Response.Cache.SetValidUntilExpires(true);
context.Response.Cache.SetCacheability(HttpCacheability.Public);
}
#region Localization
private static Regex REGEX = new Regex(#"CustomTranslate\(([^\))]*)\)", RegexOptions.Singleline | RegexOptions.Compiled);
private string TranslateScript(string text)
{
MatchCollection matches = REGEX.Matches(text);
ResourceManager manager = new ResourceManager(typeof(TranslationTest.App_GlobalResources.text));
foreach (Match match in matches)
{
object obj = manager.GetObject(match.Groups[1].Value);
if (obj != null)
{
text = text.Replace(match.Value, CleanText(obj.ToString()));
}
}
return text;
}
private static string CleanText(string text)
{
text = text.Replace("'", "\\'");
text = text.Replace("\\", "\\\\");
return text;
}
private static string ReadFile(string absolutePath)
{
if (File.Exists(absolutePath))
{
using (StreamReader reader = new StreamReader(absolutePath))
{
return reader.ReadToEnd();
}
}
return null;
}
#endregion
#region Compression
private const string GZIP = "gzip";
private const string DEFLATE = "deflate";
private static void Compress(HttpContext context)
{
if (IsEncodingAccepted(DEFLATE, context))
{
context.Response.Filter = new DeflateStream(context.Response.Filter, CompressionMode.Compress);
SetEncoding(DEFLATE, context);
}
else if (IsEncodingAccepted(GZIP, context))
{
context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);
SetEncoding(GZIP, context);
}
}
private static bool IsEncodingAccepted(string encoding, HttpContext context)
{
return context.Request.Headers["Accept-encoding"] != null && context.Request.Headers["Accept-encoding"].Contains(encoding);
}
private static void SetEncoding(string encoding, HttpContext context)
{
context.Response.AppendHeader("Content-encoding", encoding);
}
#endregion
}
}
global.asax.cs
namespace TranslationTest
{
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
Microsoft.Web.Optimization.BundleTable.Bundles.EnableDefaultBundles();
BundleConfig.RegisterBundles(System.Web.Optimization.BundleTable.Bundles);
AuthConfig.RegisterOpenAuth();
}
}
}
I hope I've covered everything, but please let me know if there's anything missing. Thanks in advance!!
Ok, I've set up everything in your example and I've got it to work but you need to use the IBundleTransform interface. The details of everything I did are posted below..
I had to create a class to handle the bundle transformation (i.e the translation) instead of allowing the default behaviour.
public class JsLocalizationTransform : IBundleTransform
{
public JsLocalizationTransform(){}
#region IBundleTransform Members
public void Process(BundleContext context, BundleResponse response)
{
string translated = TranslateScript(response.Content);
response.Content = translated;
}
#endregion
#region Localization
private static Regex REGEX = new Regex(#"CustomTranslate\(([^\))]*)\)", RegexOptions.Singleline | RegexOptions.Compiled);
private string TranslateScript(string text)
{
MatchCollection matches = REGEX.Matches(text);
ResourceManager manager = new ResourceManager(typeof(TranslationTest.App_GlobalResources.text));
foreach (Match match in matches)
{
object obj = manager.GetObject(match.Groups[1].Value);
if (obj != null)
{
text = text.Replace(match.Value, CleanText(obj.ToString()));
}
}
return text;
}
private static string CleanText(string text)
{
//text = text.Replace("'", "\\'");
text = text.Replace("\\", "\\\\");
return text;
}
#endregion
}
Then in BundleConfig.RegisterBundles method you need to create and add the bundle like this:
var extjsBundle = new Bundle("~/bundles/ExtJS").Include("~/Scripts/ExtJS/ext-all.js", "~/Scripts/ExtJS/TestForm.js");
extjsBundle.Transforms.Clear();
extjsBundle.Transforms.Add(new JsLocalizationTransform());
extjsBundle.Transforms.Add(new JsMinify());
bundles.Add(extjsBundle);
I could then remove the HttpHandler from web.config as that gets configured automatically through the bundler. I also had to make some changes to the Application_Start method in global.asax.cs
void Application_Start(object sender, EventArgs e)
{
//Microsoft.Web.Optimization.BundleTable.Bundles.EnableDefaultBundles();
BundleTable.EnableOptimizations = true; //Added this line..
BundleConfig.RegisterBundles(System.Web.Optimization.BundleTable.Bundles);
AuthConfig.RegisterOpenAuth();
}
Because the JSLocalisationTransform class is handling the bundle transformation and translation, I completely removed the ScriptTranslator class.
Hope that helps.

Fill a drop down list dynamically using Javascript/jQuery

In an ASP .NET MVC Razor view, I have a dropdown list as follows:
#Html.DropDownListFor(model => model.SelectedDeviceModel, Model.DeviceModelList)
DeviceModelList is just a SelectList.
How can I dynamically fill the DeviceModelList depending on a client side action like a button click or another drop down selection using Javascript/jQuery/Ajax?
You could externalize this dropdown into a partial:
#model MyViewModel
#Html.DropDownListFor(model => model.SelectedDeviceModel, Model.DeviceModelList)
then in your main view include it inside some container:
#model MyViewModel
...
<div id="ddlcontainer">
#Html.Partial("Foo", Model)
</div>
...
then you could have a controller action which takes some parameter and based on its value it renders this partial:
public ActionResult Foo(string someValue)
{
MyViewModel model = ... go ahead and fill your view model
return PartialView(model);
}
Now the last part is to send the AJAX request to refresh the drop down list when some event occurs. For example when the value of some other ddl changes (or something else, a button click or whatever):
$(function() {
$('#SomeOtherDdlId').change(function() {
// when the selection of some other drop down changes
// get the new value
var value = $(this).val();
// and send it as AJAX request to the newly created action
$.ajax({
url: '#Url.Action("foo")',
type: 'POST',
data: { someValue: value },
success: function(result) {
// when the AJAX succeeds refresh the ddl container with
// the partial HTML returned by the Foo controller action
$('#ddlcontainer').html(result);
}
});
});
});
Another possibility consists into using JSON. Your Foo controller action would only return some Json object containing the new key/value collection and in the success callback of the AJAX request you would refresh the drop down list. In this case you don't need to externalize it into a separate partial. For example:
$(function() {
$('#SomeOtherDdlId').change(function() {
// when the selection of some other drop down changes
// get the new value
var value = $(this).val();
// and send it as AJAX request to the newly created action
$.ajax({
url: '#Url.Action("foo")',
type: 'POST',
data: { someValue: value },
success: function(result) {
// when the AJAX succeeds refresh the dropdown list with
// the JSON values returned from the controller action
var selectedDeviceModel = $('#SelectedDeviceModel');
selectedDeviceModel.empty();
$.each(result, function(index, item) {
selectedDeviceModel.append(
$('<option/>', {
value: item.value,
text: item.text
})
);
});
}
});
});
});
and finally your Foo controller action will return Json:
public ActionResult Foo(string someValue)
{
return Json(new[] {
new { value = '1', text = 'text 1' },
new { value = '2', text = 'text 2' },
new { value = '3', text = 'text 3' }
});
}
For a similar example you may take a look at the following answer.

Categories

Resources