Check MVC Model property if it's null using Jquery - javascript

Ok I have looked a while for some answers to my question but seems like the accepted answers works for some but for me isn't.
Below is my current implementation to check if #Model.ListImages is not null
var img = #((Model != null && Model.ListImages != null).ToString().ToLower());
if (img) {
if (#Model.ListImages.Count() + this.files.length > 8) {
this.removeFile(file);
$('#errorMessage').html("Cannot upload more then 8 images for a product.");
$("#errorDiv").show();
window.scrollTo(0, 0);
}
}
The Model
public class ProductVM
{
[Required]
public int Id { get; set; }
[Required]
[Display(Name = "Category")]
public int IdCategory { get; set; }
[Required]
[Display(Name = "Collection")]
public int IdCollection { get; set; }
[Required]
[Range(0.1, 20000, ErrorMessage = "Please enter a value between 0 and 20000")]
public decimal Price { get; set; }
[Required]
[Display(Name = "Product Name")]
[StringLength(100, ErrorMessage = "Product name must contain at least {2} characters", MinimumLength = 6)]
public string Name { get; set; }
[Required]
[Display(Name = "Product Description")]
[StringLength(500, ErrorMessage = "Product name must contain at least {2} characters", MinimumLength = 25)]
public string Description { get; set; }
public HttpPostedFileBase[] Listfiles { get; set; }
public virtual IEnumerable<SelectListItem> Categories { get; set; }
public virtual IEnumerable<SelectListItem> Collections { get; set; }
public virtual IEnumerable<Reviews> ListReviews { get; set; }
public virtual ICollection<Images> ListImages { get; set; }
}

The problem is you are mixing JavaScript and Razor which ought to be avoided. It can be done if done carefully but it leads to hard to read i.e. hard to debug and maintain.
Your code is assuming the Razor will not execute based on JavaScript evaluation. However, this is not the case and the Razor statement will always attempt to evaluate.
// this looks like JavaScript with in-lined Razor.
// The Razor is executed before this JavaScript is executed.
var img = #((Model != null && Model.ListImages != null).ToString().ToLower());
// this is a JavaScript conditional based on a run-time value
if (img) {
// #Model.ListImages.Count() is evaluated by Razor BEFORE
// (and in a different context) the if(img) above.
// But there isn't a Razor condition preventing the execution of .Count()
// if ListImages is not initialized.
if (#Model.ListImages.Count() + this.files.length > 8) {
this.removeFile(file);
}
}
So you need an Razor conditional to output different JavaScript code.
#* Razor evaluated on the server while rendering the view *#
#if (Model != null && Model.ListImages != null)
{
var count = Model.ListImages.Count;
<script>
// JavaScript evaluated in the client
var images = #count; // "hardcoded" count on the server
if (images > 0)
{
removeFile()
}
</script>
}
A cleaner way to avoid the mixing is to encode the Razor value into an HTML element.
<div id="image"
data-count="#((Model != null && Model.ListImages != null) ? Model.ListImages.Count : 0)">
</div>
Then get the value in JavaScript which could run without dynamically outputting different js code.
var count = $("#image").data("count");
if (count > 0) {
removeFile();
}

var length = "#(Model.ListImages.Count())";
if(length > 0){
// do something
}

JavaScript has a tricky (if you don’t know it) way of checking conditions for truthy and falsy values. When you check for a variable directly in the condition like you did
if (img)
it doesn’t actually check if the value of the variable you provided is false or true, but if that object exists. So, even if img is false, your code will go there and you’ll get a null reference exception.
Try a simple
if (img != false)
but, as suggested in the other answer,
if (#Model && #Model.ListImages && #Model.ListImages.Count() > 0)
is better

Related

Web API MVC get query parameter from ng-table?

I've been trying to get ng-table(angular directive) work with a web api (ASP.NET MVC). I can load and page the data but the sorting or filtering won't work.
The weird thing is that the sorting or filtering will look like this in the URL:
http://localhost:46278/api/rating?count=10&filter%5Brating.name%5D=fs&page=1&sorting%5Brating.description%5D=asc
If you would "format" it, it would look like this:
filter[rating.name] = fs
sorting[rating.description] = asc
I tried to get them with a string array or a dictionary (KeyValuePair)
But I can't get the values. So I can never filter or sort the data.
I hope you can give me some advice! I appreciate your help!
I wrote a helper class to deal with this. The URL isn't formatted in a way WebAPI expects, so couldn't get the ModelBinder to parse it automatically.
From your controller, call the helpers and provide the entire URL:
// Parse sortings
var sortings = TableHelpers.ParseSortings(Request.RequestUri).ToList();
// Parse filters
var filters = TableHelpers.ParseFilters(Request.RequestUri).ToList();
And the helper class
public static class TableHelpers
{
public static IEnumerable<TableSorting> ParseSortings(Uri requestUri)
{
var regex = new Regex("sorting%5B(.+?)%5D=(asc|desc)");
var matches = regex.Matches(requestUri.AbsoluteUri);
return from Match match in matches
select new TableSorting {Field = match.Groups[1].Value, Order = match.Groups[2].Value};
}
public static IEnumerable<TableFilter> ParseFilters(Uri requestUri)
{
var regex = new Regex("filter%5B(.+?)%5D=(.+?)(?:&|\\z)");
var matches = regex.Matches(requestUri.AbsoluteUri);
return from Match match in matches
select new TableFilter {Field = match.Groups[1].Value, Value = match.Groups[2].Value};
}
}
public class TableSorting
{
public string Field { get; set; }
public string Order { get; set; }
}
public class TableFilter
{
public string Field { get; set; }
public string Value { get; set; }
}
are you asking about directive syntax or your api?
in ng-table directive, insert in <td> tag sorting or/and filtering attrs, like:
<td width="10%" data-title="'NUM'|translate" filter="{ 'num': 'text' }" sortable="'num'"><span>{{item.num}}</span></td>

How do I use JObject if the names are slightly different?

I have a JObject from JSON.NET with the following:
var jOBject = {"schedule.ID" : 1, "schedule.Name" : "NameSchedule"}
The above is what I get from using Javascript to return the ID's and values of textboxes in the MVC Form in my View.
In my controller using C#, I would like to convert it into a Schedule Object that has the following Properties:
public class Schedule {
public int ID {get;set;}
public string Name {get;set;}
}
I cannot do a
Schedule sched = jsonObject.toObject<Schedule>();
because the names are slightly different as the properties on the Jobject is prepended with 'schedule'.
Is there a query or a way to do the conversion that allows me to remove the 'schedule' in the jsonObject such that I can do the simple conversion in one line?
One simple way to get it working is to use the JsonProperty attribute to specify what JSON key you want to map to a certain C# property:
public class Schedule
{
[JsonProperty("schedule.ID")]
public int ID {get;set;}
[JsonProperty("schedule.Name")]
public string Name {get;set;}
}
Then you can just use JsonConvert.DeserializeObject to deserialize your JSON into a Schedule instance:
var schedule = JsonConvert.DeserializeObject<Schedule>(json);
Example: https://dotnetfiddle.net/Nml9be
To use different key names in the JSON, you can decorate your C# class with DataContract and DataMember attributes.
[DataContract]
public class Schedule {
[DataMember("schedule.ID")]
public int ID { get; set; }
[DataMember("schedule.Name")]
public string Name { get; set; }
}
JObject scheduleObj={schedule:{"ID" : 1, "Name" : "NameSchedule"}}
JsonSerializer seria = new JsonSerializer();
Schedule oSchedule = new Schedule();
if (ScheduleObj["Schedule"] != null)
{
oSchedule = (Schedule)seria.Deserialize(new JTokenReader(ScheduleObj["Schedule"]), typeof(Schedule));
}

Creating c# array similar to javascript array

I am new in C# and would like to know if it's possible to create an array in C# like following:
rates[0]['logic_id'] = 12;
rates[0]['line_id'] = ""
rates[0]['rate'] = rateVal;
rates[0]['changed'] = isChanged;
rates[1]['logic_id'] = 13;
rates[1]['line_id'] = ""
rates[1]['rate'] = secvalue;
rates[1]['changed'] = isChanged;
Can I create rates array in C# with such values?
EDIT:
My goal is to send rates array to a specific Web API service that is running with PHP. They accept only array with abovementioned structure. That's why I want to achieve that.
The best approach here would be to create a Rate class that is held in a List<Rate>().
public class Rate
{
public int LogicId { get; set; }
public string LineId { get; set; }
public decimal Rate { get; set; }
public bool IsChanged { get; set; }
}
public void Populate()
{
var rates = new List<Rate>();
var rate = new Rate();
rate.LogicId = 12;
rate.LineId = string.Empty;
rate.Rate = 0;
rate.IsChanged = true;
rates.Add(rate);
}
To access the values, you can loop through them:
foreach(var rate in rates)
{
//Do something with the object, like writing some values to the Console
Console.WriteLine(rate.LogicId);
Console.WriteLine(rate.Rate);
}
You could solve it using arrays, but it's someway outdated the approach.
My suggestion is that you should use a List<Dictionary<string, object>>:
var data = new List<Dictionary<string, object>>();
data.Add(new Dictionary<string, object>());
data[0].Add("rate", rateVal);
And later you can access it like JavaScript using dictionary's indexer:
var rate = data[0]["rate"];
Update
OP said:
My goal is to send rates array to a specific Web API service that is
running with PHP. They accept only array with abovementioned
structure. That's why I want to achieve that.
No problem. If you serialize that list of dictionaries using JSON.NET, you can produce a JSON which will contain an array of objects:
[{ "rate": 2 }, { "rate": 338 }]
Actually, .NET List<T> is serialized as a JSON array and a Dictionary<TKey, TValue> is serialized as a JSON object, or in other words, as an associative array.
This can depend on your specific neeeds, mut maybe you just want a list of objects
first create a class:
class Rate
{
public int LoginId { get; set; }
public int? LineId { get; set; }
public decimal RateValue { get; set; }
public bool IsChanged { get; set; }
}
Then, in any method you want, just use:
List<Rate> Rates = new List<Rate>();
Rates.Add(new Rate() {LoginId = 1, LineId = null, RateValue = Rateval, IsChanged = false});
Rates.Add(new Rate() {LoginId = 13, LineId = null, RateValue = SecVal, IsChanged = false});
EDIT
My apologies for the terrible answer, edited to account for the errors
public struct Rate
{
public int LoginId ;
public int LineId ;
public double RateValue ;
public bool IsChanged;
}
public static void makelist()
{
List<Rate> Rates = new List<Rate>();
Rates.Add(new Rate() {LoginId = 1, LineId = null, RateValue = Rateval,IsChanged = false});
}
This method will only hold data, and not hold methods like a class.
With the data types defined in the struct, memory usage stays low as its only purpose is to store data. This is a midway between a variable and a class.

Error deserializing JSON data to Dictionary <string, string>

Here is the JSON that I want to deserialize into Dictionary using native Javascript support.
string data = "{"Symptom":[true,true,true],"Action":[true,true],"AllArea":true}";
But when I attempt to deserialize using below code
Dictionary values = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize>(data);
It gives me an error stating
"Type 'System.String' is not supported for deserialization of an array"
I am using .Net Framework 3.5. Please help me getting this done.
i guess you can not convert that to a dictionary directly... i think deserializer needs a corresponding type, with intelligible property names with type,
i think you can convert to a type, then generate your dictionary, something like:
public class MyClass
{
public List<bool> Symptom { get; set; }
public List<bool> Action { get; set; }
public bool AllArea { get; set; }
public Dictionary<string, List<bool>> getDic()
{
// this is for example, and many many different may be implement
// maybe some `reflection` for add property dynamically or ...
var oDic = new Dictionary<string, List<bool>>();
oDic.Add("Symptom", this.Symptom);
oDic.Add("Action", this.Action);
oDic.Add("AllArea", new List<bool>() { AllArea });
return oDic;
}
}
then:
string data = "{\"Symptom\":[true,true,true],\"Action\":[true,true],\"AllArea\":true}";
System.Web.Script.Serialization.JavaScriptSerializer aa = new System.Web.Script.Serialization.JavaScriptSerializer();
var o = aa.Deserialize<MyClass>(data);
var dic = o.getDic();
anyhow, it was a good question

How disable parent items on dropdownlistfor?

I have a Region class like this:
public class Region
{
public int Id { get; set; }
public int Name { get; set; }
public int ParentId { get; set; }
}
And Person has region:
public class Person
{
public int Id { get; set; }
public int Name { get; set; }
public int SurName { get; set; }
public int RegionId { get; set; }
}
But, it is not like tree node. There are only 2 floors. Countries and it's sub regions - cities. I use bootstrap template.
I collect this regions like this list:
Country1 //need to disable this
City1
City2
City3
Country2 //need to disable this
City1
City2
In person create action:
Viewbag.Regions = new SelectList(MyRepository.LoadRegions(), "Id", "Name");
And in view:
#Html.DropDownListFor(model => model.RegionId, ViewBag.Regions as IEnumerable<SelectListItem>, "-", new { data_rel = "chosen", #id = "region" })
Finally, I need when dropdown opens, to disable countries, it is possible to select only cities.
How can I disable elements in dropdownlis which parentId == 0 ?
One approach you could take is to load up the Regions, remove the Parent items, and then assign the SelectList to the Viewbag.
var regions = MyRepository.LoadRegions();
/* remove parent items from regions */
ViewBag.Regions = new SelectList(regions, "Id", "Name");
EDIT I previously misunderstood the question. You want to have headers that aren't selectable. I found this question about MVC supporting OptGroups (which I think will accomplish what you're going for). Turns out the base Html.DropDown helper doesn't support it but you can write a custom one, and in the linked question there is a sample of a custom helper for this case.

Categories