I have a list of image urls that I am trying to display. I am passing the list from the controller to the view. I know that the list is being created successfully. But when it gets to the view, javascript interprets it as "*System.Collections.Generic.List1[System.String]*`" not as the actual list. This causes the images not to be displayed.
Here is the line of code that I am using to assign the list to js variable:
var imageUrls = '#Model.PicUrls';
and the controller
public ActionResult Index()
{
var pics = _ctx.Image.Select(m => m).Take(10).ToList<ImageModel>();
var picUrls = new List<string>();
for (int i = 0; i <= pics.Count - 1; i++)
{
picUrls.Add(pics[i].ImageUrl);
}
var outModel = new ViewPostViewModel
{
PicUrls = picUrls
};
return View(outModel);
I tried to return a Json object but then the page literally only displayed was the completed list.
return Json(outModel.PicUrls, JsonRequestBehavior.AllowGet);
So, the Json advice worked somewhat but it is not quite there
try it
public ActionResult Index()
{
var pics = _ctx.Image.Select(m => m.ImageUrl)
.Take(10).ToList();
var picUrls = new List();
for (int i = 0; i <= pics.Count - 1; i++)
{
picUrls.Add(pics[i]);
}
var outModel = new ViewPostViewModel
{
PicUrls = picUrls
};
return Json(outModel.PicUrls, JsonRequestBehavior.AllowGet);
}
Getting
System.Collections.Generic.List`1[System.String]
because you're model value PicUrls default ToString() implementation is to return its type.
You could store PicUrls as a JSON string, then parse to javascript array in your js.
public ActionResult Index()
{
var pics = _ctx.Image.Select(m => m).Take(10).ToList();
var picUrls = String.Empty;
for (int i = 0; i <= pics.Count - 1; i++)
{
picUrls += (picUrls != String.Empty ? ", " : "") + #"""" + pics[i].ImageUrl + #"""";
}
var outModel = new ViewPostViewModel
{
PicUrls = #"[" + picUrls + "]";
};
return View(outModel);
In your js, use
var imageUrls = JSON.parse('#Model.PicUrls');
Related
In my view, I have checkboxes and some data displayed and button on each row to approve or reject requests put up.
I want to send my integer array to my action method but this cannot be done by just sending it to action query parameters and it would be like the picture below:
public int[] Ids
{
get { return new int[] { 1, 2, 3 }; }
set {}
}
public ActionResult Approval([ModelBinder(typeof(IntArrayModelBinder))] int[] ids)
{
...
return View(...);
}
#Html.ActionLink("Approve", "Approval", new {id = item.Ids, approvalAction = "approve"})
How do I implement the checkboxes to be checked and hover of the approve/reject actionlink will show the url with ../ids=1&ids=2&ids=3 instead of System.Int32[]?
Option 1: Send your array as a comma-separated string and then split them in your action like this :
#Html.ActionLink("Approve", "Approval", new { id = string.Join("," , Ids), approvalAction = "approve" } )
your action :
public ActionResult YourAction(string id , string approvalAction)
{
var ids = id.Split(',');
//rest of your action method business
}
Option 2:
another way to achieve your exactly url is to create your URL like this :
var baseUrl = Url.Action("YourAction", "YourController", null, Request.Url.Scheme);
var uriBuilder = new UriBuilder(baseUrl);
uriBuilder.Query = string.Join("&", Ids.Select(x => "ids=" + x));
string url = uriBuilder.ToString();
url += "&approvalAction=approve"
and your action would be like this :
public ActionResult YourAction(int[] ids , string approvalAction)
{}
<script>
function multiSelect(selectedArray, action) {
if (selectedArray[0] === undefined) {
alert("You have not selected any employee");
}
//example url
//..?ids=1&ids=2&ids=3&aprovalAction=approve
else {
var param = "";
var currUrl = "";
var idUrl = "";
idUrl = "ids=" + selectedArray[0];
for (var i = 1; i < selectedArray.length; ++i) {
idUrl += "&ids=" + selectedArray[i];
}
switch (action) {
case "Approve":
param = "approve";
break;
case "Reject":
param = "reject";
break;
}
currUrl = "approvalAction=" + param;
window.location.href = "?" + idUrl + "&" + currUrl;
}
}
</script>
<script>
$('#MultiApproveBtn').click(function () {
var selected = $('input[type=checkbox]:checked').map(function (_, el) {
return $(el).val();
}).get();
var x = document.getElementById("MultiApproveBtn").value;
//alert(selected);
multiSelect(selected, x);
})
</script>
<script>
$('#MultiRejectBtn').click(function () {
var selected = $('input[type=checkbox]:checked').map(function (_, el) {
return $(el).val();
}).get();
var x = document.getElementById("MultiRejectBtn").value;
//alert(selected);
multiSelect(selected, x);
})
</script>
I am working on user roles using Asp.net MVC. I am stuck while working on Admin section. I have mentioned one question above and the second question is similar which is Using the generic type 'System.Collections.Generic.List' requires 1 type arguments
Here is my code.
public ActionResult Index(string searchStringUserNameOrEmail, string currentFilter, int? page)
{
try
{
int intPage = 1;
int intPageSize = 5;
int intTotalPageCount = 0;
if (searchStringUserNameOrEmail != null)
{
intPage = 1;
}
else
{
if (currentFilter != null)
{
searchStringUserNameOrEmail = currentFilter;
intPage = page ?? 1;
}
else
{
searchStringUserNameOrEmail = "";
intPage = page ?? 1;
}
}
ViewBag.CurrentFilter = searchStringUserNameOrEmail;
List col_UserDTO = new List();
int intSkip = (intPage - 1) * intPageSize;
intTotalPageCount = UserManager.Users
.Where(x => x.UserName.Contains(searchStringUserNameOrEmail))
.Count();
var result = UserManager.Users
.Where(x => x.UserName.Contains(searchStringUserNameOrEmail))
.OrderBy(x => x.UserName)
.Skip(intSkip)
.Take(intPageSize)
.ToList();
foreach (var item in result)
{
ExpandedUserDTO objUserDTO = new ExpandedUserDTO();
objUserDTO.UserName = item.UserName;
objUserDTO.Email = item.Email;
objUserDTO.LockoutEndDateUtc = item.LockoutEndDateUtc;
col_UserDTO.Add(objUserDTO);
}
// Set the number of pages
// Error appears here
var _UserDTOAsIPagedList =
new StaticPagedList
(
col_UserDTO, intPage, intPageSize, intTotalPageCount
);
return View(_UserDTOAsIPagedList);
}
catch (Exception ex)
{
ModelState.AddModelError(string.Empty, "Error: " + ex);
List col_UserDTO = new List(); // Error appears here
return View(col_UserDTO.ToPagedList(1, 25));
}
}
#endregion
`
StaticPagedList is generic. You need to supply the type of collection(for col_UserDTO), in your case List:
var _UserDTOAsIPagedList =
new StaticPagedList<List<ExpandedUserDTO>>
(
col_UserDTO, intPage, intPageSize, intTotalPageCount
);
See http://www.programering.com/a/MTN2gDNwATM.html
You may need to change List col_UserDTO references to List<ExpandedUserDTO> col_UserDTO
Use this instead
var _UserDTOAsIPagedList =
new StaticPagedList<ExpandedUserDTO>
(
col_UserDTO, intPage, intPageSize, intTotalPageCount
);
I'm trying create a function to generate HTML file for multi-language menu. The code can work but only problem is its taking too long to compile. The flow is, this function will be called in the Global.asax file (process before start the program)
I suspect it caused by the looping process. So please advice me about the optimization. Thank you in advance. Here is the code.
public static void GenerateMenu(string strPath)
{
string[] tempCateHTML = new string[] { "_temp_menu_en.cshtml", "_temp_menu_bm.cshtml", "_temp_menu_ch.cshtml" }; //temporary file names
string[] cateHTML = new string[] { "_menu_en.cshtml", "_menu_bm.cshtml", "_menu_ch.cshtml" };
for (int i = 0; i < 3; i++)
{
using (EFContext ctx = new EFContext())
{
List<int> parentId = new List<int>();
List<Category> parentCategory = ctx.Database.SqlQuery<Category>
("select CategoryId, category_name, category_nameBM, category_nameCH from dbo.lCategories where thread_parent = 0").ToList();
StringWriter sWriter = new StringWriter();
using (HtmlTextWriter wt = new HtmlTextWriter(sWriter))
{
foreach (Category cate in parentCategory)
{
string[] columnParent = new string[] { cate.Category_Name, cate.Category_NameBM, cate.Category_NameCH };
wt.RenderBeginTag(HtmlTextWriterTag.Li); //<li>
wt.AddAttribute(HtmlTextWriterAttribute.Href, "#");
wt.RenderBeginTag(HtmlTextWriterTag.A); //<a>
wt.Write(columnParent[i]);
wt.RenderEndTag();//</a>
wt.RenderBeginTag(HtmlTextWriterTag.Ul);//<ul>
List<Category> childCategoryL1 = ctx.Database.SqlQuery<Category>
("select CategoryId, category_name, category_nameBM, category_nameCH from dbo.lCategories where thread_parent = {0}", cate.CategoryID).ToList();
foreach (Category root in childCategoryL1)
{
string[] columnChild1 = new string[] { root.Category_Name, root.Category_NameBM, root.Category_NameCH };
wt.RenderBeginTag(HtmlTextWriterTag.Li);//<li>
wt.AddAttribute(HtmlTextWriterAttribute.Href, "#");
wt.RenderBeginTag(HtmlTextWriterTag.A);//<a>
wt.Write(columnChild1[i]);
wt.RenderEndTag();//</a>
List<Category> childCategoryL2 = ctx.Database.SqlQuery<Category>
("select CategoryId, category_name, category_nameBM, category_nameCH from dbo.lCategories where thread_parent = {0}", root.CategoryID).ToList();
if (childCategoryL2.Count > 0)
{
wt.RenderBeginTag(HtmlTextWriterTag.Ul);//<ul>
foreach (Category child1 in childCategoryL2)
{
string[] columnChild2 = new string[] { child1.Category_Name, child1.Category_NameBM, child1.Category_NameCH };
wt.RenderBeginTag(HtmlTextWriterTag.Li);//<li>
wt.AddAttribute(HtmlTextWriterAttribute.Href, "#");
wt.RenderBeginTag(HtmlTextWriterTag.A);//<a>
wt.Write(columnChild2[i]);
wt.RenderEndTag();//</a>
List<Category> childCategoryL3 = ctx.Database.SqlQuery<Category>
("select CategoryId, category_name, category_nameBM, category_nameCH from dbo.lCategories where thread_parent = {0}", child1.CategoryID).ToList();
if (childCategoryL3.Count > 0)
{
wt.RenderBeginTag(HtmlTextWriterTag.Ul);//<ul>
foreach (Category child2 in childCategoryL3)
{
string[] columnChild3 = new string[] { child2.Category_Name, child2.Category_NameBM, child2.Category_NameCH };
wt.RenderBeginTag(HtmlTextWriterTag.Li);//<li>
wt.AddAttribute(HtmlTextWriterAttribute.Href, "#");
wt.RenderBeginTag(HtmlTextWriterTag.A);//<a>
wt.Write(columnChild3[i]);
wt.RenderEndTag();//</a>
wt.RenderEndTag();//</li>
}
wt.RenderEndTag();//</ul>
}
wt.RenderEndTag();//</li>
}
wt.RenderEndTag();//</ul>
}
wt.RenderEndTag();//</li>
}
wt.RenderEndTag();//</ul>
wt.RenderEndTag();//</li>
}
}
string menuHTML = sWriter.ToString();
string filePath = Path.Combine(strPath, #"Views\Shared\CacheData\CateMenu\");
new FileInfo(filePath).Directory.Create(); //create new folder
var menuPath = String.Format("{0}{1}", filePath, tempCateHTML[i]); //create multiple HTML files for multiple language
using (FileStream fs = new FileStream(menuPath, FileMode.Append, FileAccess.Write))
{
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(menuHTML);
sw.Flush();
sw.Close();
fs.Close();
}
if (!File.Exists(filePath + cateHTML[i]))
{
using (File.Create(filePath + cateHTML[i]))
{
//create dummy file if the file doesnt exists
}
}
File.Replace(menuPath, filePath + cateHTML[i], filePath + cateHTML[i] + ".bac");
}
}
}
it's a long process. So really Thank you for the time
Actuall I've already found the solution for my problem. The solution was built tree menu based on this method. Thank you for the help.
While i build the Project, It have a error like this:
Server Error in '/' Application.
The model item passed into the dictionary is of type
'System.Data.DataTable', but this dictionary requires a model item of
type 'System.Collections.Generic.IList`1[TLayout.Models.DemoTable]'.
This is my Controller
public ActionResult Index()
{
var dm = new DemoTable();
string connstring = "Server=localhost;Port=5432;User Id=postgres;Password=123456;Database=test";
NpgsqlConnection conn = new NpgsqlConnection(connstring);
conn.Open();
string sql = "select * from demo";
NpgsqlDataAdapter da = new NpgsqlDataAdapter(sql, conn);
ds.Reset();
da.Fill(ds);
dt = ds.Tables[0];
var demoid = dm.demoid.ToString();
var demoname = dm.demoname;
for (int i = 0; i < dt.Rows.Count; i++)
{
List<DataTable> dtb = new List<DataTable>();
demoid = dt.Rows[i]["demoid"].ToString();
demoname = dt.Rows[i]["demoname"].ToString();
dtb.Add(dt);
}
return View(dt);
}
This is my View, to show data to layout:
foreach (var item in Model)
{
fields.Add(Html.X().ModelField().Mapping(#item.demoid.ToString()).Name("grid-alarm"));
fields.Add(Html.X().ModelField().Mapping(#item.demoname.ToString()).Name("grid-check"));
}
var list = dt.AsEnumerable()
.Where(row => (int)row["demoid"] > 5)
.Select(row => new
{
demoid = Convert.ToInt32(row["demoid"]),
demoname = row["demoname"] != null ?
row["demoname"].ToString() :
String.Empty
}).ToList();
Or you can define class:
public class myClass
{
public int demoid;
public string demoname;
}
and then:
List<myClass> list = dt.AsEnumerable()
.Where(row => (int)row["demoid"] > 5)
.Select(row => new myClass
{
demoid = Convert.ToInt32(row["demoid"]),
demoname = row["demoname"] != null ?
row["demoname"].ToString() :
String.Empty
}).ToList<myClass>();
In an ASP.NET MVC3 application, if I wanted to model bind my form post data to an ExpandoObject (or my own object derived from DynamicObject where I implement my own Try... members) would I need to write my own custom model binder?
If I do:
public ActionResult Save(ExpandoObject form)
{
....
}
The value of form is null.
Or if I have:
public class MyDynamicThing : DynamicObject
{
public int Id { get; set; }
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// Set breakpoint here but doesn't get hit when model binding
return base.TrySetMember(binder, value);
}
}
...and in my controller:
public ActionResult Save(MyDynamicThing form)
{
....
}
In the above example Id is set to the value from the form. However if I set a breakpoint in TrySetMember this doesn't get hit.
Are there any magical incantations I can invoke to coerce the built-in model binder to work with ExpandoObjects or my own classes derived from DynamicObject?
I could resort to picking up the raw form post collection but I have to serialise this data to JSON which would mean an extra and untidy step to harvest those values.
No, this is not possible with the built-in model binder. You could of course write a custom model binder. The only property that the built-in model binder is capable of binding is the one that it seems from the MyDynamicThing type and that's why it can only set the Id property. It has no knowledge of other properties.
Try this:
public class ExpandoObjectBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException("bindingContext");
IDictionary<string, object> model = new ExpandoObject();
string modelName = bindingContext.ModelName;
var form = controllerContext.HttpContext.Request.Unvalidated.Form;
var keys = form.AllKeys.Where(k => k.StartsWith(modelName + "."));
Debug.Write("ExpandoObjectBinder keys count is " + keys.Count());
foreach (var key in keys)
{
var propName = key.Replace(model + ".", "");
model.Add(propName, form[key]);
}
if (model.Count == 0)
throw new Exception("Data is empty.");
return model;
}
}
Register the binder mvc initialization :
ModelBinders.Binders.Add(typeof(ExpandoObject), new ExpandoObjectBinder());
Type support added (int, byte, long, decimal, string, array and subobjects):
public class ExpandoObjectBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException("bindingContext");
string modelName = bindingContext.ModelName;
var form = controllerContext.HttpContext.Request.Unvalidated.Form;
var model = ParseProperties(modelName, form);
return model;
}
public object ParseProperties(string modelName, NameValueCollection form)
{
var keys = form.AllKeys.Where(k => k.StartsWith(modelName + "."));
Debug.WriteLine("ExpandoObjectBinder keys count is " + keys.Count() + " for " + modelName);
IDictionary<string, object> model = new ExpandoObject();
List<string> subModelNames = new List<string>();
List<string> arrModelNames = new List<string>();
//ModelName: Dialog.Attributes[0].Options
foreach (var key in keys)
{
//Dialog.Attributes[0].Options.Byte
//Dialog.Attributes[0].Options.Inner.Byte
//Dialog.Attributes[0].Options.Inner.Integer
//Dialog.Attributes[0].Options.SimpleArray[0]
//Dialog.Attributes[0].Options.SimpleArray[1]
var propName = key.Replace(modelName + ".", "");
//Byte
//Inner.Byte
//Inner.Integer
//SimpleArray[0]
//SimpleArray[1]
if (!(propName.Contains('[') || propName.Contains('.')))
{
model.Add(propName, GetValue(form, key));
}
//array (can allow sub objects)
if (propName.Contains('['))
{
var names = propName.Split('[');
var arrModelName = names[0];
if (!arrModelNames.Contains(arrModelName))
arrModelNames.Add(arrModelName);
}
//not array but can has sub objects
if (!propName.Contains('[') && propName.Contains('.'))
{
var names = propName.Split('.');
var subModelName = names[0];
if (!subModelNames.Contains(subModelName))
subModelNames.Add(subModelName);
}
}
foreach (var subModelName in subModelNames)
{
var key = modelName + "." + subModelName;
object val = form[key];
val = ParseProperties(key, form);
model.Add(subModelName, val);
}
foreach (var arrModelName in arrModelNames)
{
//Dialog.Attributes[0].Options.SimpleArray[
var key = modelName + "." + arrModelName + "[";
var arrKeys = form.AllKeys.Where(k => k.StartsWith(key));
var isComplexArray = false;
int length = 0;
foreach (var arrKey in arrKeys)
{
var aKey = arrKey.Replace(key, "");
if (aKey.Contains("."))
isComplexArray = true;
var parsed = aKey.Split(']');
var num = int.Parse(parsed[0]);
if (num > length)
length = num;
}
List<object> vals = new List<object>();
if (isComplexArray)
{
for (int i = 0; i < length + 1; i++)
{
var arrKey = key + i + "]";
object val = ParseProperties(arrKey, form);
vals.Add(val);
}
}
else
{
for (int i = 0; i < length + 1; i++)
{
var arrKey = key + i + "]";
vals.Add(GetValue(form, arrKey));
}
}
model.Add(arrModelName, vals);
}
return model;
}
object GetValue(NameValueCollection form, string key)
{
object val = form[key];
if (decimal.TryParse(form[key], out decimal decimalVal))
val = decimalVal;
if (long.TryParse(form[key], out long longVal))
val = longVal;
if (int.TryParse(form[key], out int intVal))
val = intVal;
if (byte.TryParse(form[key], out byte byteVal))
val = byteVal;
if (bool.TryParse(form[key], out bool boolVal))
val = boolVal;
return val;
}
}