Passing of model from razor to javascript - very strange error - javascript

I tried to pass the selected model in the HTML table row right into javascript function, including conversion to a JSON. The conversion failed because of the problem below.
Also, I freaked out for more than 6 hours trying to understand why it's not working. Now I know what caused the problem, no idea how to fix it.
Here is what I tried (simple and easy):
<table class="table table-hover">
<thead align="center">
<tr>
<th scope="col">AssetID</th>
<th scope="col">Loaction</th>
<th scope="col">AreaIn</th>
<th scope="col">Rooms</th>
<th scope="col">ImageURL</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody align="center">
#foreach (var a in #Model.OwnAssetsList)
{
String[] assetArray = new String[8] { a.AssetID.ToString(), a.OwnerID.ToString(), a.OwnerPublicKey.ToString(), a.Loaction.ToString(), a.AreaIn.ToString(), a.Rooms.ToString(), a.ImageURL.ToString(), a.Price.ToString() };
<tr>
<td>#a.AssetID</td>
<td>#a.Loaction</td>
<td>#a.AreaIn</td>
<td>#a.Rooms</td>
<td><a target="_blank" href=#a.ImageURL>Click</a></td>
<td><button class="btn btn-primary" data-toggle="modal" data-target="#exampleModalLong" onclick="offerContract(#a.Loaction/* or #a.ImageURL*/)">Offer Contract</button></td>
</tr>
}
</tbody>
In Javascript:
#section scripts
{
<script type="text/javascript">
function offerContract(param)
{
document.getElementById("dialogAssetID").innerHTML = "Asset No:".bold()+param.AssetID;
document.getElementById("dialogOwnerAddress").innerHTML="Your Public Key:" +param.OwnerID;
}
</script>
}
The javascript function fails if and only if I passing #a.Loaction or #a.ImageURL.
Here is the error in the console: 'Uncaught SyntaxError: missing ) after argument list'.
The rest properties of the model passed successfully.
The '#a.Loaction' and '#a.ImageURL' working fine in the HTML table
I am adding now the model and the table scheme:
public class Asset
{
[Key]
public int AssetID { get; set; }
[Required]
public int OwnerID { get; set; }
[Required]
public string OwnerPublicKey { get; set; }
[Required]
public string Loaction { get; set; }
[Required]
public int AreaIn { get; set; }
[Required]
public int Rooms { get; set; }
[Required]
public string ImageURL { get; set; }
[Required]
public double Price { get; set; }
}
I will appreciate any help. More than 6 hours spent on this issue.

in your Razor page, you basically need to pre-generate a javascript object that you will then pass along to your JS:
in your scripts section is a good place:
#section scripts {
<script type="text/javascript">
var data = #Json.Serialize(#Model.OwnAssetsList);
function offerContract(index)
{
document.getElementById("dialogAssetID").innerHTML = "Asset No:".bold() + data[index].assetId;
document.getElementById("dialogOwnerAddress").innerHTML="Your Public Key:" + data[index].ownerId;
}
</script>
Your Razor then could look something like this (note, since you are opting for foreach, there was no direct way to get current iteration index, so I had to introduce one myself):
#{var i = 0} //
#foreach (var a in #Model.OwnAssetsList)
{
<tr>
...
<td><button class="btn btn-primary" data-toggle="modal" data-target="#exampleModalLong" onclick="offerContract(#i)">Offer Contract</button></td>
</tr>
i += 1; // next iteration
}
}
UPD: if you absolutely must pass strings from Razor to JS, you will need to quote them:
<td><button class="btn btn-primary" data-toggle="modal" data-target="#exampleModalLong" onclick="offerContract('#a.Loaction')">Offer Contract</button></td>
I suggest single quotes so Razor does not get confused

I found another way to pass the problematic properties:
<tbody align="center">
#{ int i = 0;}
#foreach (var a in #Model.OwnAssetsList)
{
string loaction = "loc" + i;
string url = "url" + i;
<tr>
<td>#a.AssetID</td>
<td id=#loaction>#a.Loaction</td>
<td>#a.AreaIn</td>
<td>#a.Rooms</td>
<td><a id=#url target="_blank" href=#a.ImageURL>Click</a></td>
<td><button class="btn btn-primary" data-toggle="modal" data-target="#exampleModalLong" onclick="offerContract( #i)">Offer Contract</button></td>
</tr>
i++;
}
</tbody>
And in the function:
function offerContract(param)
{
var idLoac = "#loc" + param;
var idUrl = "#url" + param;
var demdloc = $(idLoac).text();
var demdurl = $(idUrl).attr("href");
document.getElementById("dialogAssetID").innerHTML = "Asset No:".bold() + demdloc;
document.getElementById("dialogOwnerID").innerHTML = "Your ID:".bold() + demdurl;
}
And the properties are perfectly passing.

Related

How to Pass ViewModel from MVC Html to Jquery?

I have a cshtml file which uses for each loops from the value of the model that comes from controller.My cshtml code is below:-
<tbody>
#foreach (var item model.TechnicianInvoice)
{
<tr>
<td>#item.Name</td>
#foreach (var rate in item.Rates)
{
<td class="td10"><span class="prefix">$</span><input type="text" class="form-control my-input" value="#rate.Rate.ToString("0.00")"></td>
}
<td><a class="btn btn-sm" href="#" data-action="ShowPayTableModal" data-id="#item.Id" name="#item.Name">view</a></td>
<td><a class="updateRate" data-id="#item">update</a></td>
</tr>
}
</tbody>
And model.TechnicianInvoice is a ist of view Model of:
public class TechnicianInvoiceViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<TechRateViewModel> Rates { get; set; }
}
public class TechRateViewModel
{
public int Id { get; set; }
public double Rate { get; set; }
}
Now What I need is when I click on the update button the current foreach value of model.Technician should be passed into jquery. Currently I am using data-id = #item but when I console log this value only shows TechnicianInvoiceViewModel . My jquery code is
$(".updateRate").on("click", function () {
var data = $(this).attr("data-id");
console.log(data);
});
How Can I do this?
The problem ist that you want to parse a C# model into Javascript.
When you do data-id = #item, C# is asked for the string value of the item. But what do you expect this value to be? The Id? Then you should go for data-id = #item.Id. But there are plenty other options, it's also possible to return for example a JSON by implementing #item.getJSON() ...
Long story told short: You need to specify which value of your item you want to parse to your JavaScript ;)

How to display data from model in td based off select list item in another td

I have a separate TR and inside, a TD from the rest of my table. I have some data in my model that contains a list of strings, and also a list of IDs (not sure if I need the list of IDS for this) and I would like to display on the lower Tr's td a specific part of the list, based off of the selection of a SelectListItem in the table row's td above it.. i.e. If a user select's a list item of X, I want the TD below to display "X's help description" (which like I mentioned earlier, is being stored inside a list of strings in my model)
I am not sure if I should be doing this in Razor, Javascript, or something else. Can anyone give me some tips? Below is some code.
View:
<div class="row">
<div class="col-md-12" style="overflow-y:scroll">
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>Terminal</th>
<th>Command</th>
<th>Command Value</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td>#Html.DropDownListFor(o => o.TerminalsDDL, Model.TerminalsDDL, new { id = "ddlTerminalID", #class = "form-control" })</td>
<td>#Html.DropDownListFor(o => o.TerminalCommandLookupsDDL, Model.TerminalCommandLookupsDDL, new {id = "ddlCommandValue", #class = "form-control" })</td>
<td>#Html.TextBoxFor(o => o.UserEnteredTerminalCommands, new { Class = "form-control", Id = "cmdValueValue"})</td>
<td> <input id="btnSaveTerminalCommand" type="button" value="Insert" class="btn btn-primary" /> </td>
</tr>
<tr>
<td colspan="4" id="helpDescript">#Html.DisplayFor(model => model.HelpDescription)</td>
</tr>
</tbody>
</table>
</div>
</div>
VM:
public TerminalCommandVM()
{
//Terminals Drop Down List
TerminalsDDL = new List<SelectListItem>();
//Terminal Commands Drop Down List
TerminalCommandLookupsDDL = new List<SelectListItem>();
//Terminal Command Values list
TerminalCommandValues = new List<SelectListItem>();
}
public TerminalCommand TerminalCommand { get; set; }
public List<TerminalCommand> TerminalCommands { get; set; }
[Display(Name = "Terminal ID")]
public List<SelectListItem> TerminalsDDL { get; set; }
[Display(Name = "Command")]
public List<SelectListItem> TerminalCommandLookupsDDL { get; set; }
public List<SelectListItem> TerminalCommandValues { get; set; }
public string UserEnteredTerminalCommands { get; set; }
public List<string> HelpDescription { get; set; }
public List<int> HelpDescriptionID { get; set; }
}
The DisplayFor I want populated is the one with the ID = "helpDescript", and the select list item that should dictate which help descript is displayed has the ID = "ddlCommandValue".
As of now, helpDescript is displaying the entire list (obviously).
If anyone needs any other code or more information, please let me know.
Try the following. In the dropdown change event call the action to display the value and in the success function display the value in label
$("#ddlCommandValue").change(function () {
var obj = {
valueToPass: $(this).val()
};
$.ajax({
url: '/Home/GetValueToDisplayInlabel',
contentType: 'application/json; charset=utf-8',
type: 'POST',
data: JSON.stringify(obj),
cache: false,
success: function (result) {
$("#helpDescript").html(result);
},
error: function () {
alert("Error");
}
});

Get values from an Html table and map to a C# List using jQuery

I have an MVC project where I'm rendering the data using a table in my partial view as:
<table id="tblUserSettings" class="table table-bordered CmtTable">
<thead>
<tr>
<th>User Name</th>
<th>Country</th>
<th>System (s)</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
#if (Model == null)
{
<tr></tr>
}
else
{
foreach (var item in Model)
{
<tr>
<td><input type="hidden" id="usrId" value="#item.UserId" />
#item.UserName</td>
<td> <input type="hidden" id="usrCountryKey" value="#item.UserCountryKey" style="display:none"/>
#item.UserCountryName</td>
<td> <input type="hidden" id="usrSourceSystemKey" value="#item.UserSourceSystemKey" />
#item.UserSourceSystemDescription</td>
<td><a onclick='DeleteUserSettingsRow();'><i class='fa fa-times'></i> Delete</a><a onclick='EditUserSettingsPopup();'><i class='fa fa-pencil'></i> Edit</a></td>
</tr>
}
}
</tbody>
</table>
I'm going to save the values from this table into the database and need to call the AddUserSettingsaction method in controller as:
[HttpPost, Route("AddUserSettings")]
public ActionResult AddUserSettings(IEnumerable<UserSettings> request)
{
AddUserSettingsRequest apiRequest = null;
return View();
}
The model of UserSettings is as follows:
public class UserSettings
{
public UserSettings();
public string UserId { get; set; }
public string UserName { get; set; }
public string UserCountryKey { get; set; }
public string UserCountryName { get; set; }
public string UserSourceSystemKey { get; set; }
public string UserSourceSystemDescription { get; set; }
}
I need to save the data from the table (including the hidden fields) into the database using jQuery, so I have created a function and calling it as:
<button type="button" id="btnAdd" onclick="SaveUserSettings();"><i class="fa fa-save"></i> Save</button>
function SaveUserSettings()
{
debugger;
var userSettings = [];
$("table#tblUserSettings tr").each(function (i, v) {
userSettings[i] = [];
$(this).children('td').each(function (ii, vv)
{
userSettings[i][ii] = $(this).text();
});
})
alert(userSettings);
$.ajax({
url: '#Url.Action("AddUserSettings", "Admin")',
type: "POST",
contentType: "application/json;",
data: JSON.stringify(userSettings),
success : function (result)
{
//alert(result);
},
error: function (result)
{
//alert(result);
}
});
}
With the above SaveUserSettings() function, I can get the values which are not hidden, but I need to create an array which contains the hidden properties as well and can be sent with the ajax request to the controller as the parameter. How can I get the hidden fields and create an array mapped to the IEnumerable request of my controller?
Provided the javascript is in the partial view, you can set your userSettings directly against the model, for example:
var userSettings = #Html.Raw(JsonConvert.SerializeObject(Model));
This will then serialize your object into JSON and it will be passed to the browser, where you can then use it to pass it back to the server in jQuery without having to go through each row in the table.

Deleting from breeze/knockout table produces "Cannot read property 'BoardName' of null"

I have been using simple and clean access to removing items in a table populated from a breeze data service. Everything worked well until I started including navigation properties in the displayed table. Now whenever I use the delete functionality I get an error of Uncaught TypeError: Cannot read property 'BoardName' of null.
My database entities are set as:
public class SpecificAdapter
{
public int Id { get; set; }
public string PbaNumber { get; set; }
public int NumberOfPorts { get; set; }
public int AdapterId { get; set; }
public virtual Adapter Adapter { get; set; }
}
public class Adapter
{
public int Id { get; set; }
public string BoardName { get; set; }
public string DeviceId { get; set; }
public virtual ICollection<SpecificAdapter> SpecificAdapters { get; set; }
}
I am using a data service base in Breezejs this way:
var loadSpecificAdaptersTable = function () {
return em.executeQuery(breeze.EntityQuery.from('SpecificAdapters').expand('Adapter'));
};
Loaded in the view model like this:
adaptersDataService.loadSpecificAdaptersTable()
.then(function (data) { specificAdapters(data.results); })
.fail(function (error) { logger.error(error.message, "loadSpecificAdaptersTable failed during initialization"); });
I map it in the html like this:
<table class="table tablesorter">
<thead>
<tr>
<th data-bind="sort: {arr: specificAdapters, prop: 'Adapter().BoardName'}">Board Name</th>
<th data-bind="sort: {arr: specificAdapters, prop: 'PbaNumber'}">Pba Number</th>
<th data-bind="sort: {arr: specificAdapters, prop: 'NumberOfPorts'}"># Ports</th>
<th data-bind="sort: {arr: specificAdapters, prop: 'FirmwareVersion'}">Firmware Version</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: specificAdapters">
<tr>
<td data-bind="text: Adapter().BoardName"></td>
<td data-bind="text: PbaNumber"></td>
<td data-bind="text: NumberOfPorts"></td>
<td data-bind="text: FirmwareVersion"></td>
<td>
<button data-bind="click: $parent.editSpecificAdapter" class="btn">Edit</button>
</td>
<td>
<button data-bind="click: $parent.deleteSpecificAdapter" class="btn">Delete</button>
</td>
</tr>
</tbody>
</table>
Previous to Adapter().BoardName being added as a reference in the table, I could click the delete button and everything worked. Now I get an error. The delete logic is as:
var deleteSpecificAdapter = function (item) {
item.entityAspect.setDeleted();
specificAdapters.remove(item);
};
The error is thrown upon item.entityAspect.setDeleted(); being run. Does adding the data-binding to Adapter().BoardName change the item variable in a way that doesn't map back well enough to use? Do I need to have different logic for determining the actual item or do I need to bind the click event differently in order to get the specific, non-remapped item from the foreach?
By binding to the BoardName the way you are it is creating a timing issue. Since the value is being cleared before the parent context updates fully it throws an error. There are a few ways to get around this -
<td data-bind="with: Adapter"><span data-bind="text: BoardName"></span></td>
This will only bind to the BoardName property when adapter is populated
<td data-bind="if: Adapter"><span data-bind="text: BoardName"></span></td>
This will only evaluate the inner-span's data-binding when Adapter has a value.

How to dynamically add row to html table

I got a ASP.net MVC 4.0 web application which enable user to dynamically add rows to html table.
In my view:
$('.del').live('click', function () {
id--;
var rowCount = $('#options-table tr').length;
if (rowCount > 2) {
$(this).parent().parent().remove();
}
});
$('.add').live('click', function () {
id++;
var master = $(this).parents("table.dynatable");
// Get a new row based on the prototype row
var prot = master.find(".prototype").clone();
prot.attr("class", "")
prot.find(".id").attr("value", id);
master.find("tbody").append(prot);
});
<table class="dynatable" id="options-table" width="100%" style="text-align:center" border="1">
<tr class="prototype">
<%:Html.EditorFor(m => Model.ChillerDetails)%> //referring to the template
</tr>
<thead>
</table>
In my template:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<GMIS.Models.GMISEBModels.ChillerPlantDetails>" %>
<div id="ChillerPlantDetails">
<td><%: Html.EditorFor(m => m.ChillerAge) %></td>
<td><%: Html.EditorFor(m => m.ChillerBrand) %></td>
<td><%: Html.EditorFor(m => m.ChillerCapacity) %></td>
<td><%: Html.EditorFor(m => m.ChillerRefrigerant) %></td>
<td>
<a href="#" class="add"><img src="<%= Url.Content("~/Content/Images/add.png") %>"/> <a href="#" class="del"><img src="<%= Url.Content("~/Content/Images/remove.png") %>"/>
</td>
</div>
In my Model:
public class AddHealthCheckFormModel
{
public List<ChillerPlantDetails> ChillerDetails { get; set; }
}
public class ChillerPlantDetails
{
//[Required(ErrorMessage = "Please enter Chiller Capacity.")]
[Display(Name = "Chiller Capacity")]
public string ChillerCapacity { get; set; }
//[Required(ErrorMessage = "Please enter Age of Chiller.")]
[Display(Name = "Age of Chiller")]
public string ChillerAge { get; set; }
//[Required(ErrorMessage = "Please enter Chiller Brand.")]
[Display(Name = "Chiller Brand")]
public string ChillerBrand { get; set; }
//[Required(ErrorMessage = "Please enter Chiller Refrigerant.")]
[Display(Name = "Chiller Refrigerant")]
public string ChillerRefrigerant { get; set; }
}
Now the question comes to how can I capture the data in the dynamically added rows into my controller and save into database?
You can use following View which will add new record using HTTP Post instead of Ajax.
Replacing it with Ajax.BeginForm with appropriate parameters will use the Ajax instead of plain post request.
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<table class="list-chiller-record">
#for (int i = 0; i < this.Model.ChillerDetails.Count; i++)
{
if (i == 0)
{
<tr class="chiller-record-template" style="display:none">
<td>#Html.EditorFor(x=>x.ChillerDetails[i].ChillerAge)</td>
<td>#Html.EditorFor(x=>x.ChillerDetails[i].ChillerBrand)</td>
<td>#Html.EditorFor(x=>x.ChillerDetails[i].ChillerCapacity)</td>
<td>#Html.EditorFor(x=>x.ChillerDetails[i].ChillerRefrigerant)</td>
</tr>
}
<tr class="chiller-record">
<td>#Html.EditorFor(x=>x.ChillerDetails[i].ChillerAge)</td>
<td>#Html.EditorFor(x=>x.ChillerDetails[i].ChillerBrand)</td>
<td>#Html.EditorFor(x=>x.ChillerDetails[i].ChillerCapacity)</td>
<td>#Html.EditorFor(x=>x.ChillerDetails[i].ChillerRefrigerant)</td>
</tr>
}
</table>
<br />
<input type="button" class="add-button" name="add" value="Add" />
<input type="submit" class="save-button" name="save" value="save" />
}
Add add new row:
<script type="text/javascript">
$(document).ready(function () {
var count = 2;
$('.add-button').click(function () {
count++;
var template = $('.chiller-record-template').clone()
template.find('input[type=text]').val('');
$.each(template.find('input[type=text]'), function () {
var name = $(this).attr('name');
name = name.replace('0', count - 1);
$(this).attr('name', name);
});
$('.list-chiller-record').append(template);
template.removeClass('chiller-record-template').addClass('chiller-record').show();
})
});
</script>
Your Action Could be like this:
[HttpPost]
public ActionResult AddHealthCheck(AddHealthCheckFormModel model)
{
if (ModelState.IsValid)
{
HealthCheckRepository healthCheckRepository = new HealthCheckRepository();
healthCheckRepository.save(model);
}
return this.View(model);
}
And in repository you can actually save the data in database. You can use EF or any other ORM for this.

Categories