How to create 'n' child objects and parent at the same view? - c#

I'm using asp.net mvc razor, and I'm making a view to create a parent's object, but along creating the parent I need to create 'n' child objects. How can I do this exactly?
I will reinforce that I'm not expecting to display the object's, I need to create them in one go, I say this only because I saw too many misunderstanding in my research.
Let me explain exactly what i need to do:
I have a model called 'Car', this model have a child element: ICollection< Extra >, when the user will insert a new 'Car' he may be capable of insert 'Extra' stuff before inserting the 'Car' to the database. And the 'Extra' could have N elements, so it's not fixed.
My model as example:
[Table("Car")]
public partial class Car
{
[Key]
public int IdCar { get; set; }
[Required]
[StringLength(10)]
[Display(Name = "Car")]
public string DsCar { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Extra> Extra{ get; set; }
}
Here's a view example of what i want to do that could help:
Insert Page
I wish to avoid the page refreshing effect if possible too.

After some researching I did not find anything suitable for my case, so I ended doing some code by myself.
(I was not able to search to much, I believe there must be a better answer somewhere)
As I want to make them reusable i created them in a partial view.
<div class="form-group">
#{
TempData["ParentToken"] = ViewBag.Token;
Html.RenderAction("EstoqueOpcional", "Estoques");
}
</div>
In my partial view I created an AjaxForms:
#using (Ajax.BeginForm("EstoqueOpcionalCreate", new AjaxOptions() { OnSuccess = "RegistroAdicionadoOpcional()", OnFailure = "ConectionFailed()", HttpMethod = "Post" })){
#Html.Hidden("PageToken", (object)TempData["ParentToken"])
<!-- MY FIELDS -->
<input type="submit" value="Atualizar" class="btn btn-save" />
...
I have a page token in every page so I can create TempDatas using them without problem of the user opening multiple tabs of the same view. (ViewBag's isn't available because I'm not able to send anything back to the page).
Those are the scripts I created to control the display and stuff. (Most of them are still strongly typed as I still not refined my code yet)
<script>
function RegistroAdicionadoOpcional() {
var newData = $("#dsopcional").val();
var pass = true;
$("#tableEstoqueOpcional .CheckData").each(function () {
if ($(this).html() == newData)
pass = false;
});
if (pass) {
$("#tableEstoqueOpcional").append("<tr><td class=\"CheckData\">" + newData + "</td>" +
"<td class=\"grid-cell temp-cell\" style=\"padding: 0px !important;\">" + "Remover" + "</td></tr>");
$("#dsopcional").val("");
$("#dsopcional").focus();
}
else {
Message("Error", "Esse valor já foi inserido.");
$("#dsopcional").focus();
}
}
function RemoveDataOpcional(value) {
$.ajax({
url: "/Estoques/RemoverOpcional",
data: { opcional: value, PageToken: $("#PageToken").val() },
cache: false,
type: "POST",
timeout: 5000,
success: function (data) {
if (data == "True") {
$("#tableEstoqueOpcional .CheckData").each(function () {
if ($(this).html() == value)
$(this).parent('tr').remove();
});
}
else
Message("Error", "Não foi possível remover o valor escolhido, tente atualizar a página.");
},
error: function (reponse) {
Message("Error", "Não foi possível remover o valor selecionado, se o erro persistir tente recarregar a página.");
}
});
}
#{
var regs = "";
if (TempData["EstoqueOpcional"] != null)
{
foreach (var item in (List<Models.EstoqueOpcional>)TempData["EstoqueOpcional"])
{
regs += "<tr><td class=\\\"CheckData\\\">" + item.DsOpcional + "</td>" +
"<td class=\\\"grid-cell temp-cell\\\" style=\\\"padding: 0px !important;\\\">" + "Remover" + "</td></tr>";
}
}
TempData["DisplayEstoque"] = regs;
}
$(document).ready(function () {
var text = "#Html.Raw(HttpUtility.HtmlDecode(TempData["DisplayEstoque"].ToString()))";
$("#tableEstoqueOpcional").append(text);
});
In my controller I created those methods to control the values in the TempData:
public ActionResult EstoqueOpcional()
{
return PartialView(new EstoqueOpcional());
}
[HttpPost]
public bool EstoqueOpcionalCreate(EstoqueOpcional estoqueOpcional, string PageToken)
{
List<EstoqueOpcional> estoqueOpcionals = new List<EstoqueOpcional>();
if (TempData["EstoqueOpcional" + PageToken] != null)
estoqueOpcionals.AddRange((List<EstoqueOpcional>)TempData["EstoqueOpcional" + PageToken]);
if (estoqueOpcionals.Where(x => x.DsOpcional == estoqueOpcional.DsOpcional).Count() == 0)
estoqueOpcionals.Add(estoqueOpcional);
TempData["EstoqueOpcional" + PageToken] = estoqueOpcionals;
return true;
}
public bool RemoverOpcional(string opcional, string PageToken)
{
try
{
if (TempData["EstoqueOpcional" + PageToken] != null)
{
List<EstoqueOpcional> estoqueOpcionals = (List<EstoqueOpcional>)TempData["EstoqueOpcional" + PageToken];
estoqueOpcionals.RemoveAll(x => x.DsOpcional == opcional);
TempData["EstoqueOpcional" + PageToken] = estoqueOpcionals;
}
return true;
}
catch
{
return false;
}
}
In the update button button of my main model I have done like this:
List<EstoqueOpcional> estoqueOpcionals = new List<EstoqueOpcional>();
if (TempData["EstoqueOpcional" + PageToken] != null)
estoqueOpcionals.AddRange((List<EstoqueOpcional>)TempData["EstoqueOpcional" + PageToken]);
foreach (var estoqueopcional in estoqueOpcionals)
{
estoqueopcional.CdEstoque = estoque.CdEstoque;
EstoqueOpcional estoqueopcionaltemp = db.EstoqueOpcional.Where(x => x.DsOpcional == estoqueopcional.DsOpcional).FirstOrDefault();
if (estoqueopcionaltemp == null)
db.EstoqueOpcional.Add(estoqueopcional);
}
foreach (var item in db.EstoqueOpcional.Where(x => x.CdEstoque == estoque.CdEstoque).ToList()
.Where(x => !estoqueOpcionals.Any(y => y.DsOpcional == x.DsOpcional)).ToList())
{
db.EstoqueOpcional.Remove(item);
}
The create method it's very familiar with the update one.
I still believe there must be a easier way to do this, but this was suitable for me.
Image Result
Any advice or suggestion is welcome.
Thanks.

Related

how to implement Treeview in razor page

previous quest
i make tree view in razor page
As I tried to call multiple tree views simultaneously in cshtml, I ended up using a recursive function.
program sequence
Get all tree data from DB
Bind tree data to TreeNode
Display in html using recursive function
So while I was looking for it, I found something that can make html directly in the back and I'm going to use it.
When creating jsonresult, "There was a case where the js function itself was not recognized due to a problem.
I want to know if there is a way
Questions
Is the way I'm building my tree a very strange way now?
public class TreeNode
{
public List<TreeNode> subTreeNodes { get; set; }
public string dataName { get; set; }
public bool deployment { get; set; }
public string board_id { get; set; }
public TreeNode(string dName)
{
dataName = dName;
deployment = false;
}
}
cshtml.cs
public IActionResult OnGet()
{
//if(session)
List<TreeNode> treeData;
IQueryable<tbl_tree> iqueryTree;
iqueryTree = _context.tbl_tree.Where(x => x.upcode == "AAAAAA");
var datas = iqueryTree.ToList();
tree_List = new List<TreeNode>();
for (int i = 0; i < datas.Count; i++)
{
TreeNode treeNode = new TreeNode(datas[i].name);
treeNode.subTreeNodes = ConstructorData(datas[i].icd11);
treeNode.board_id = datas[i].icd11;
tree_List.Add(treeNode);
}
TempData.Set("TreeData", tree_List);
jsonData = UpdateRecursiveData(tree_List[1]);
return Page();
}
public List<TreeNode> ConstructorData(string str)
{
List<TreeNode> treeNodes = new List<TreeNode>();
IQueryable<tbl_tree> iqueryTree;
iqueryTree = _context.tbl_tree.Where(x => x.upcode == str);
var datas = iqueryTree.ToList();
for (int i = 0; i < datas.Count; i++)
{
TreeNode treeNode = new TreeNode(datas[i].name);
treeNode.board_id = datas[i].icd11;
treeNode.subTreeNodes = ConstructorData(datas[i].icd11);
treeNodes.Add(treeNode);
}
return treeNodes;
}
How will you package "in jsonresult?"
JsonResult UpdateRecursiveData(TreeNode tn)
{
JsonResult jsonResult = new JsonResult(
"<input type = 'checkbox' onclick = requestMyAction( '" +tn.board_id+"', this.checked, 'loader-"+tn.dataName+"');' />" +
"<div class='loader' style='display: none;' id='loader-'" +tn.dataName+ "'> "+tn.dataName+ "</div>" +
"<br />");
//if (tn.deployment)
//{
//for (int i = 0; i<tn.subTreeNodes.Count; i++)
// UpdateRecursiveData(tn.subTreeNodes[i]);
//}
return jsonResult;
}
this cshtml
<input type="checkbox"
onclick="requestMyAction('#Model.tree_List[0].board_id', this.checked,
'loader-#Model.tree_List[0].dataName');" />
<div class="loader" style="display: none;" id="loader-#Model.tree_List[0].dataName">
#Model.tree_List[0]
</div>
<div id="data">
#Html.Raw(Model.jsonData.Value)
</div>
remove all
this error is syntax error js complier is not working in VS studio
string strResult =
"<div style='padding: 0 0 0 10px ;display:"+defaultView+"'id='"+tn.dataName+tn.upCode+"'>" +
"<input type='checkbox'style='visibility:"+subCheck+";'onclick=requestMyAction('"+tn.icd11+"',this.checked,'"+tn.dataName+tn.upCode+"');>" +
"<span onclick = 'CallViewBorad("+tn.board_Id + ")' >"+tn.dataName+" </span>";

Unsure on how to access Include data in C# Linq

Evening all,
I was hoping that someone could help me along with a project that I am working on.
Just before I really start, I just want to make it absolutely clear, I have never done anything like this before past dabbling at home, I am not a C# developer or Database administrator. So please excuse any breaks from best practice, this is the total of 4 weeks worth of learning and banging my head on the desk trying to follow quiet a confusing topic.
So I have (somehow) ended up being tasked with creating a number of websites, and in an effort to make it easier for myself I have tried to create a "templated" system where I use a number of partial pages/parts in a layout page to drive the website via data.
I have created the below database structure, trying to think of all the things I will need, such as turning parts on and off and creating a control that creates the menu structure.
Model Diagram
of the back of that I have created the below class that creates all of the various view models that I want to pass to each of the partials in my layout (there are multiple dependant on the site hence the parts instead of one giant layout).
public class PageDetails
{
public static async Task<DataPageDetailsVM> Get(int companyID, ControllerContext controllerContext)
{
using (var dimensionContext = new DimensionContext())
{
var cDNAddress = await CDNAddress.Get();
var aPIAddress = await APIAddress.Get();
var routeDetails = new RouteDetails(controllerContext);
var canonicalPath = CanonicalPath.Get(routeDetails);
var pageDetailsVM = await dimensionContext.PageDetail
.Where(pde => pde.PageAction.PageController.PageArea.Company.CompanyID == companyID
&& (pde.PageAction.PageController.PageArea.Area == (routeDetails.Area ?? "Home")
&& !pde.PageAction.PageController.PageArea.Excluded)
&& (pde.PageAction.PageController.Controller == routeDetails.Controller
&& !pde.PageAction.PageController.Excluded)
&& (pde.PageAction.Action == routeDetails.Action
&& !pde.PageAction.Excluded))
.Select(pde => new DataPageDetailsVM
{
PageActionID = pde.PageActionID,
CDNAddress = cDNAddress,
APIAddress = aPIAddress,
Title = pde.Title,
FormattedTitle = pde.FormattedTitle,
TagLine = pde.TagLine,
StrapLine = pde.StrapLine,
Latitude = pde.PageAction.PageController.PageArea.Company.CompanyAddress
.Select(sca => sca.Latitude)
.FirstOrDefault(),
Longitude = pde.PageAction.PageController.PageArea.Company.CompanyAddress
.Select(sca => sca.Longitude)
.FirstOrDefault(),
DataRouteVM = new DataRouteVM
{
PrimaryDomain = pde.PageAction.PageController.PageArea.Company.CompanySettings
.Select(scs => scs.PrimaryDomain)
.FirstOrDefault(),
Area = (routeDetails.Area ?? "Home"),
Controller = routeDetails.Controller,
Action = routeDetails.Action
},
DataCompanyVM = new DataCompanyVM
{
CompanyID = companyID,
ShortName = pde.PageAction.PageController.PageArea.Company.ShortName,
LongName = pde.PageAction.PageController.PageArea.Company.LongName
},
PartHeaderVM = new PartHeaderVM
{
ShortName = pde.PageAction.PageController.PageArea.Company.ShortName,
CDNAddress = cDNAddress
},
PartMetaVM = pde.PageAction.PageController.PageArea.Company.CompanySettings
.Select(cse => new PartMetaVM
{
ShortName = pde.PageAction.PageController.PageArea.Company.ShortName,
ShortDescription = pde.ShortDescription,
LongDescription = pde.LongDescription,
Keywords = pde.Keywords,
MsValidate = cse.MsValidate,
FbAppID = cse.FbAppID,
CanonicalPath = cse.PrimaryDomain + "/" + canonicalPath,
OgImage = cse.PrimaryDomain + "/" + pde.OgImage,
ThemeColor = cse.ThemeColor
})
.FirstOrDefault(),
PartLinksVM = new PartLinksVM
{
CanonicalPath = pde.PageAction.PageController.PageArea.Company.CompanySettings
.Select(cse => cse.PrimaryDomain)
.FirstOrDefault() + "/" + canonicalPath,
},
PartBreadcrumbVM = new PartBreadcrumbVM
{
BreadcrumbImage = cDNAddress + pde.BreadcrumbImage,
Area = (routeDetails.Area ?? "Home"),
Controller = routeDetails.Controller,
Action = routeDetails.Action,
Title = pde.Title,
TagLine = pde.TagLine
},
PartFooterVM = new PartFooterVM
{
CDNAddress = cDNAddress,
DataCompanyAddressVM = pde.PageAction.PageController.PageArea.Company.CompanyAddress
.Select(cad => new DataCompanyAddressVM
{
ShortName = cad.Company.ShortName,
LongName = cad.Company.LongName,
Registration = cad.Company.Registration,
AddressLine1 = cad.AddressLine1,
AddressLine2 = cad.AddressLine2,
AddressLine3 = cad.AddressLine3,
AddressLine4 = cad.AddressLine4,
Postcode = cad.Postcode,
Phone = cad.Phone
})
.FirstOrDefault(),
DataCompanySocialVM = pde.PageAction.PageController.PageArea.Company.CompanySocial
.Select(cso => new DataCompanySocialVM
{
FacebookAddress = cso.FacebookAddress,
LinkedInAddress = cso.LinkedInAddress,
TwitterAddress = cso.LinkedInAddress
})
.FirstOrDefault()
}
})
.FirstAsync();
return pageDetailsVM;
}
}
}
My question is I am having to do multiple selects such as:
pde.PageAction.PageController.PageArea.Company.CompanySettings
.Select(scs => scs.PrimaryDomain)
.FirstOrDefault(),
When I am pretty sure I can use .Include at the top some how and the use a . noted value instead.
But I cant seem to work out how.
I hope that makes sense, and any feedback would be appreciated.
Edit - So just to build on this, basically I have a layout that builds all the bits off a layoutvm class then pass all the "bits" to all the partials
<body class="loading-overlay-showing" data-plugin-page-transition data-loading-overlay data-plugin-options="{'hideDelay': 500}">
#Html.Partial("~/Views/Shared/DisplayTemplates/_Loader.cshtml")
<div class="body">
#if (isCustomerArea)
{
#Html.Partial("~/Areas/Customer/Views/Shared/DisplayTemplates/_Header.cshtml", Model.DataPageDetailsVM.PartHeaderVM)
}
else
{
#Html.Partial("~/Views/Shared/DisplayTemplates/_Header.cshtml", Model.DataPageDetailsVM.PartHeaderVM)
}
<main>
#if ((ViewContext.RouteData.Values["controller"].ToString() == "Home" && ViewContext.RouteData.Values["action"].ToString() != "Index") || ViewContext.RouteData.Values["controller"].ToString() != "Home")
{
#Html.Partial("~/Views/Shared/DisplayTemplates/_Breadcrumb.cshtml", Model.DataPageDetailsVM.PartBreadcrumbVM)
}
#RenderBody()
</main>
#if (isCustomerArea)
{
#Html.Partial("~/Areas/Customer/Views/Shared/DisplayTemplates/_Footer.cshtml", Model.DataPageDetailsVM.PartFooterVM)
}
else
{
#Html.Partial("~/Views/Shared/DisplayTemplates/_Footer.cshtml", Model.DataPageDetailsVM.PartFooterVM)
}
</div>
<section>
#Scripts.Render(Model.DataPageDetailsVM.CDNAddress + "Common/js-footer")
#Scripts.Render(Model.DataPageDetailsVM.CDNAddress + CompanyDetails.COMPANYID + "/js-footer")
#RenderSection("scripts", required: false)
</section>
I have a layout class:
public abstract class LayoutVM
{
public virtual DataPageDetailsVM DataPageDetailsVM { get; set; }
}
which pulls all the bits in.
Then each page inherits from that layout vm:
public class PageRetailVM : LayoutVM
{
public SuggestedServicesVM SuggestedServicesVM { get; set; }
}
then my page controller becomes very simple, not only do I get access to all the layout data, but the code for the page becomes really small:
[HttpGet]
[AllowAnonymous]
public async Task<ActionResult> Retail()
{
PageRetailVM pageRetailVM = new PageRetailVM
{
DataPageDetailsVM = await PageDetails.Get(CompanyDetails.COMPANYID, ControllerContext),
SuggestedServicesVM = await PartSuggestedServices.Get(CompanyDetails.COMPANYID, ControllerContext)
};
return View(pageRetailVM);
}
That is what the PageDetails class is for
Include() allows you to indicate which related entities should be read from the database as part of the same query. It allows you to make eager loading for performance purposes.
DbContext class enables lazy loading by default, when the entity is first read, related data isn't retrieved. However, the first time you attempt to access a navigation property, the data required for that navigation property is automatically retrieved. This results in multiple queries sent to the database.
You could Include() related data that you need and simply save it to a variable for further processing.

High Chart Issue on VS 2008

I have a serious Issue :(, I'm using High Charts controls on VS 2008 and everytime I made run to the web application I got that "Silly" RunTime Error :
missing compiler required member 'system.runtime.compilerservices.extensionattribute.ctor.
I don't know the reason for that and I will appreciate any help !.
First of All I would like to thank everyone who commented on my stupid issue.Especially, wergeld (#wergeld),who gave me the first melody of the symphony:)...
My solution is a work around on that stupid compile error by writing the Javascript implementation of the chart using StringBuilder Class and this is the main idea of the work around.
lets stop chit chat :) and look at my humble work around:
First, I inserted all my Chart Implementation into a single class called "ChartImplementor.Cs" as following:
public enum ChartTypes
{
pie,
column,
bar
}
public class ChartImplementor
{
#region Member Variables
string _title = String.Empty;
string _subTitle = String.Empty;
string _YTitle = string.Empty;
string _XTitle = string.Empty;
#endregion
#region Properties
public string ChartTitle
{
set { _subTitle = value; }
get { return _subTitle; }
}
public string ChartSubTitle
{
set { _title = value; }
get { return _title; }
}
public string YTitle
{
set { _YTitle = value; }
get { return _YTitle; }
}
public string XTitle
{
set { _XTitle = value; }
get { return _XTitle; }
}
#endregion
public string GenerateChartJS(ChartImplementor _chartObj,
ChartTypes _chartType,
Dictionary<object, object> _myXYDictionary, string _divID)
{
string newX_String = string.Empty;
string newY_String = string.Empty;
string ChartScript = string.Empty;
StringBuilder builder = new StringBuilder();
if (_chartType == ChartTypes.column || _chartType == ChartTypes.bar)
{
foreach (KeyValuePair<object, object> pair in _myXYDictionary)
{
string newXValue = String.Format("'{0}',", _myXYDictionary.Keys);
newX_String += newXValue;
}
string XAxisData = string.Format("[{0}]", newX_String);
builder.Append("<script language='javascript' type='text/javascript'>");
builder.Append("$(function () {");
builder.Append("$('#" + _divID + "').highcharts({");
builder.Append("chart: {type:'" + _chartType + "'},");
builder.Append("title: {text:'" + _chartObj.ChartTitle + "'},");
builder.Append("subtitle: {text:'" + _chartObj.ChartSubTitle + "'},");
builder.Append("xAxis: {title: { text:'" + _chartObj.XTitle + "'},categories:" + XAxisData + ",labels:{enabled:false}},");
builder.Append("yAxis: { min: 0, title: { text:'" + _chartObj.YTitle + "'}},");
builder.Append("tooltip: {headerFormat: '<span style=font-size:10px></span>");
builder.Append("<table style=direction: rtl>',");
builder.Append("pointFormat: '<tr><td style=color:{series.color};padding:0>{series.name}: </td><td style=padding:0><b>{point.y:.1f}</b></td></tr>',");
builder.Append("footerFormat: '</table>',");
//builder.Append("shared: true,");
builder.Append("useHTML: true},");
builder.Append("plotOptions: { column: { pointPadding: 0.2, borderWidth: 0}},");
builder.Append("series:[");
foreach (KeyValuePair<object, object> pair in _myXYDictionary)
{
string newXValue = String.Format("'{0}'", pair.Key);
builder.Append("{ name:");
builder.Append("" + newXValue + "");
builder.Append(",data: ");
builder.Append("[" + pair.Value + "]},");
}
builder.Append("]});");
builder.Append("});");
builder.Append("</script>");
ChartScript = builder.ToString();
}
else if (_chartType == ChartTypes.pie)
{
builder.Append("<script language='javascript' type='text/javascript'>");
builder.Append("$(function () {");
builder.Append("$('#" + _divID + "').highcharts({");
builder.Append("chart: {plotBackgroundColor: null,plotBorderWidth: null,plotShadow: false},");
builder.Append("title: {text:'" + _chartObj.ChartTitle + "'},");
//{series.name}:
builder.Append("tooltip: { pointFormat: '<b{point.percentage:.1f}%</b>'},");
builder.Append("plotOptions: { pie: {allowPointSelect: true,cursor: 'pointer',dataLabels: { enabled: true, color: '#000000',connectorColor: '#000000', format: '<b>{point.name}</b>: {point.percentage:.1f} %'}}},");
builder.Append("series:[{type: 'pie',data:[");
foreach (KeyValuePair<object, object> pair in _myXYDictionary)
{
string newXValue = String.Format("['{0}',{1}],", pair.Key, pair.Value);
builder.Append(newXValue);
}
builder.Append("]}] });");
builder.Append("});");
builder.Append("</script>");
ChartScript = builder.ToString();
}
return ChartScript;
}
}
As it can be seen from the class that the target method contains 4 parameters:
1.An instance of the ChartImplementer Class.
2.An Object from ChartTypes Enumeration.
3.An Object od a dictionary that its key and value are from an Object DataTypes(This Dictionary will take the X/Y Cordinates of the chart for Binding it).
4.The ID of the Control which will populate the Chart staff.
I have implemented the Datasource of the chart in a Dictionary Control and I passed it as a parameter in the Target Page As Following:
protected void ImageButtonPopulateChart_Click(object sender, ImageClickEventArgs e)
{
int? genderID = null;
Dictionary<object, object> myXyDataObjects = new Dictionary<object, object>();
ChartImplementor charting = new ChartImplementor()
{
ChartTitle = "A digram illustrates Employees ",
ChartSubTitle = "HSBC Bank.",
XTitle = "Employees",
YTitle = "Salaries"
};
var chartQuery = SchoolDC.usp_Chart_Report(SchoolID, genderID, statusID).ToList();
foreach (var item in chartQuery)
{
myXyDataObjects.Add(item.LevelName, item.stCount);
}
ScriptManager.RegisterStartupScript(UpdatePanel1,
UpdatePanel1.GetType(),
"script",charting.GenerateChartJS(charting, ChartTypes.column, myXyDataObjects, "container"), // container is the ID of the Div Control which will populate the Chart.
false);
}
This is the .aspx page :
<body>
<form id="form1" runat="server">
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto">
</div>
<asp:ImageButton ID="ImageButtonPopulateChart" runat="server" onclick="ImageButtonPopulateChart_Click" />
</form>
</body>
N.B: To be able to populate the Chart you need to invoke Highcharts.Js Script, and Exporting.Js Script which it is responsible for exporting the Chart in many different Formats(I like that feature:) ).
RIP Steve Jobs said,We're just enthusiastic about what we do.I'm very enthusiastic about sharing my solution to you here, so please if you revise my code and find something that can make the code looks more better or even any other crazy idea don't hesitate to advice me :).
I wish a happy day for everyone.

Why do I get an "$ is not defined" error?

I got an ActionResult TabNotes which returns a View for a tab which shows notes from a database in a grid. On the tab is a button for ActionResult CreateNote, which returns a PartialView and after saving the note I redirect back to the ActionResult TabNotes with
return RedirectToAction("TabNotes", new { modelEntity = "Phrase", id = itemId});
However, when it goes to the action result TabNotes using this redirect it does not show the grid. The javascript gives the following error
Uncaught ReferenceError: $ is not defined (anonymous function)
Uncaught ReferenceError: ko is not defined (anonymous function)
This does not happen the first time it goes to ActionResult. Using breakpoints the following part of the ActionResult TabNotes:
[...]
Model.Grid.url = Url.Action("TabNoteData", new { id = Model.meta.entity, itemId = Model.meta.id.Value});
}
return View("TabNotes", Model);
}
gives the same input values in Model for the first time and the second time. Where can this error come from?
Edit: Firebug shows the following errors:
prompt aborted by user
throw Components.Exception...by user", Cr.NS_ERROR_NOT_AVAILABLE); nsPrompter.js (regel 462 <Systeem>
$ is not defined
$(document).ready(function(){$('#tblTN...tes/44?cmd=refresh" id="TNPhrase44"> 44?mod...=Phrase (regel 2)
ko is not defined
var viewModel=ko.mapping.fromJ...],"buttons":[],"PostAction":null}}); 44?mod...=Phrase (regel 12)
Below is the javascript and code
#model test.Web.Framework.Areas.Administration.Models.TabNotesModel
#using (UI.DocumentReadyScript())
{
if (Model.meta.id.HasValue)
{
UI.jQuery("#tbl" + Model.meta.modelname).flexigrid(Model.Grid);
}
}
<form method="post" action="#Url.Action("TabNotes", new { cmd = "refresh" })" id="#Model.meta.modelname">
<div class="ui-state-highlight ui-corner-all highlight" data-bind="visible: meta.message">
<span class="ui-icon ui-icon-info"></span><strong data-bind="text: meta.message">
</strong>
</div>
#using (UI.BeginBlock("Administation.TabNotes", UI.Label("Notes", "Notes").ToString(), test.Web.Framework.Core.enumIcons.pencil, false, false))
{
<table id="#("tbl" + Model.meta.modelname)">
</table>
}
</form>
<script type="text/javascript">
(function() {
var viewModel=ko.mapping.fromJS(#Html.Raw(UI.JavascriptEncode(Model)));
viewModel.getData=function() { return ko.mapping.toJSON( this ); };
viewModel.setData=function(data){
$('#tbl'+this.meta.modelname()).flexigrid( data.Grid);
ko.mapping.updateFromJS(this,data);
};
$('##Model.meta.modelname').koform({viewmodel: viewModel , validate : {errorElement:'p' } } );
$('##Model.meta.modelname').koform('applyBindings');
$('#load-partial').click(function() {
$('#partial').load('#Url.Action("CreateNote", "Entity", new {itemId = #Model.meta.id, modelEntity = "Phrase"})');
});
})();
</script>
<div id="partial"></div>
<button type="button" id="load-partial">Create Note</button>
'
public ActionResult CreateNote(
[ModelBinder(typeof(Models.JsonModelBinder))]
NoteModel Model, string cmd, long? itemId, string modelEntity)
{
if (cmd == "Save")
{
Model.meta.message = "Note saved";
test.Database.User User = UserRepository.GetUser(1);
Entity entity = NotesRepository.GetEntity("Phrase");
NotesRepository.StoreNote(Model.subject, Model.text, User, entity, itemId);
return RedirectToAction("TabNotes", new { modelEntity = "Phrase", id = itemId});
}
Model.meta.modelname = "CreateNote";
Model.meta.JsViewModelType = "EditNoteModel";
Model.meta.PostAction = Url.Action("CreateNote", new { cmd = "Save", itemId = itemId});
return PartialView("CreateNotePartial",Model);
}
'
public ActionResult TabNotes([ModelBinder(typeof(Models.JsonModelBinder))]
TabNotesModel Model, string cmd, string modelEntity, long? id)
{
if (modelEntity != null)
{
Model.meta.entity = modelEntity;
}
Entity entity = NotesRepository.GetEntity(Model.meta.entity);
if (id.HasValue)
{
Model.meta.id = id;
}
if (Model.meta.id.HasValue)
{
Model.meta.modelname = "TN" + Model.meta.entity + Model.meta.id.Value.ToString();
Dictionary<string, object> defaultValues = new Dictionary<string, object>();
defaultValues.Add("Entity", entity.EntityId);
defaultValues.Add("ItemId", Model.meta.id.Value);
Entity noteEntity = NotesRepository.GetEntity("Note");
var grid = UI.GetEntityFlexiGrid(noteEntity, true, true, true, true, defaultValues);
grid.buttons.Clear();
//grid.buttons.Add(new Button { onpress = "CreateNote", action = Url.Action("CreateNote"), name = "CreateNote", postdata = new { meta = Model.meta }});
grid.title = "";
Model.Grid = grid;
Model.Grid.url = Url.Action("TabNoteData", new { id = Model.meta.entity, itemId = Model.meta.id.Value});
}
return View("TabNotes", Model);
}
'
public GridResult TabNoteData(string id, long itemId, FlexigridRequest request, string cmd)
{
GridResult returnValue = null;
var entity = NotesRepository.GetEntity(id);
Entity noteEntity = NotesRepository.GetEntity("Note");
//var Acess = UIRepository.GetEntityAccess(id);
FlexigridConfiguration grid;
Dictionary<string, object> defaultValues = new Dictionary<string, object>();
defaultValues.Add("Entity", entity.EntityId);
defaultValues.Add("ItemId",itemId);
grid = UI.GetEntityFlexiGrid(noteEntity, true, true, true, true, defaultValues);
IQueryable q = NotesRepository.GetNotes(entity.EntityId, itemId);
var sortField = entity.EntityFields.SingleOrDefault(c => c.Name == request.sortname);
if (sortField == null)
{
request.sortname = grid.sortname;
}
IQueryable qdata = null;
if (!string.IsNullOrEmpty(request.sortname) && request.sortname != "undefined")
{
switch (request.sortorder)
{
case enumFlexigridRequestSortOrder.asc:
qdata = q.OrderBy(request.sortname + " ascending");
break;
case enumFlexigridRequestSortOrder.desc:
qdata = q.OrderBy(request.sortname + " descending");
break;
}
}
if (!string.IsNullOrEmpty(request.query) && !string.IsNullOrEmpty(request.qtype))
{
qdata = qdata.Where(request.qtype.SanitizeFieldExpression() + ".Contains(#0)", request.query);
}
if (request.q != null && request.q.Length > 0)
{
for (int i = 0; i < request.q.Length; i++)
{
var type = UIRepository.GetType(id);
var property = type.GetProperty(request.q[i]);
System.ComponentModel.TypeConverter tc = System.ComponentModel.TypeDescriptor.GetConverter(property.PropertyType);
string sv = request.v[i];
if (sv == null || sv == "null")
{
qdata = qdata.Where(request.q[i].SanitizeFieldExpression() + "=#0", (object)null);
}
else
{
object v = tc.ConvertFromString(sv);
qdata = qdata.Where(request.q[i].SanitizeFieldExpression() + "=#0", v);
}
}
}
string settingName = "Grid." + id + ".Rp";
var setting = UIRepository.GetQuery<test.Database.UserSetting>().SingleOrDefault(uc => uc.CreatedById == CurrentUser.UserId && uc.Name == settingName);
if (setting == null)
{
setting = UIRepository.Create<test.Database.UserSetting>();
setting.Name = settingName;
setting.Value = request.rp.ToString();
UIRepository.Add(setting);
}
else
{
if (request.rp.ToString() != setting.Value)
{
setting.Value = request.rp.ToString();
UIRepository.Update(setting);
}
}
int rowId = 0;
var datarows = new List<object>();
foreach (var record in qdata.Skip((request.page - 1) * request.rp).Take(request.rp).GetData())
{
var cellValues = new List<object>();
foreach (var gc in grid.colModel.OrderBy(c => c.di))
{
cellValues.Add(gc.ToString(UI, record));
}
var row = new { id = rowId, cell = cellValues.ToArray() };
datarows.Add(row);
rowId++;
}
returnValue = Grid(request.page, qdata.Count(), datarows.ToList());
return returnValue;
}
That error can only be caused be one of three things:
Your JavaScript file is not being properly loaded into your page
You have a botched version of jQuery. This could happen because someone edited the core file, or a plugin may have overwritten the $ variable.
You have JavaScript running before the page is fully loaded, and as such, before jQuery is fully loaded.
You should check the Firebug net panel to see if the file is actually being loaded properly. If not, it will be highlighted red and will say "404" beside it. If the file is loading properly, that means that the issue is number 2.
Make sure all javascript code is being run inside a code block such as:
$(document).ready(function () {
//your code here
});
This will ensure that your code is being loaded after jQuery has been initialized.
One final thing to check is to make sure that you are not loading any plugins before you load jQuery. Plugins extend the "$" object, so if you load a plugin before loading jQuery core, then you'll get the error you described.
So to avoid that you can use a "bodyguard" function like the following:
( function($) {
//We can now use $ as I implemented the bodyguard!
$(document).ready(function() {
//your code...
});
} ) ( jQuery );

JSON post works in IE, not in FF

I have an asp.net MVC app. One of the forms posts json data to a public method (not an action, perhaps it will be later) on the controller. This works great in IE 8. However, it does not work in Firefox 3.5.
The view is a list of jquery sortable objects inside of a form. Here is a stripped down version of the form:
<form class="cmxform" id="UserForm" method="post" action="/Home/Index">
//...the <li> objects that are sortable
<input type="submit" value="Save Changes" onclick="SaveLinks();" />
</form>
Here is the javascript to fire when the button is clicked. /Home/ProcessLinks is a public method in the controller, and Visible and Invisible is a parameter being passed to the method:
function SaveLinks() {
var VisibleList = document.getElementById('sortable1');
var InvsibleList = document.getElementById('sortable2');
for (var i = 0; i < VisibleList.childNodes.length; i++) {
var link = {};
link.id = VisibleList.childNodes[i].childNodes[1].innerText;
link.title = VisibleList.childNodes[i].childNodes[2].innerText;
link.description = VisibleList.childNodes[i].childNodes[3].innerText;
link.url = VisibleList.childNodes[i].childNodes[4].innerText;
link.order = i + 1;
$.post("/Home/ProcessLinks/Visible", $.toJSON(link), function(data, testStatus) {
/*This is where the user can be notified that the item was saved successfully*/
//alert(link.id + " has been updated");
window.location.reload();
}, "text");
}
for (var i = 0; i < InvsibleList.childNodes.length; i++) {
var link = {};
link.id = InvsibleList.childNodes[i].childNodes[1].innerText;
link.title = InvsibleList.childNodes[i].childNodes[2].innerText;
link.description = InvsibleList.childNodes[i].childNodes[3].innerText;
link.url = InvsibleList.childNodes[i].childNodes[4].innerText;
link.order = i + 1;
$.post("/Home/ProcessLinks/Invisible", $.toJSON(link), function(data, testStatus) {
/*This is where the user can be notified that the item was saved successfully*/
//alert(link.id + " has been updated");
window.location.reload();
}, "text");
}
}
It is my belief that the above method does not get triggered when in Firefox, as the breakpoints I place with Firebug don't get hit.
For fun, here is my serverside function:
public string ProcessLinks(string id)
{
string Type = id;
string json = Request.Form[0];
var serializer = new DataContractJsonSerializer(typeof(JsonObject));
var memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(json));
JsonObject item = (JsonObject)serializer.ReadObject(memoryStream);
memoryStream.Close();
return "hello";
}
And my custom class JsonObject:
[DataContract]
public class JsonObject
{
[DataMember]
internal int id { get; set; }
[DataMember]
internal string title { get; set; }
[DataMember]
internal string description { get; set; }
[DataMember]
internal string order { get; set; }
[DataMember]
internal string url { get; set; }
}
Do you have any idea what I'm doing wrong? I can't seem to nail it down.
Firefox does not support innerText. Use innerHTML instead.
Another possible reason is the following HTML:
<div>
<span>foo</span>
<span>bar</span>
</div>
will have the following structure in IE
div
|---span(childNode[0])
| |
| '---text---foo
|
'---span(childNode[1])
|
'---text---bar
while in all other browsers including firefox it will have the following structure:
div
|---text(childNode[0])---newline and tabs
|
|---span(childNode[1])
| |
| '---text---foo
|
|---text(childNode[2])---newline and tabs
|
'---span(childNode[3])
|
'---text---bar
This ridiculous behavior is mandated by the W3C spec. So IE is technically wrong here.
Now, I notice in your code you make assumptions about childNode indexing without checking element.nodeName. That could be where the problem lies.
Update:
after looking at the code you uploaded I removed the <input type="submit... button from the form and added a button tag outside the form like this:
</form>
<button onclick="SaveLinks();">Save Changes</button>
After click this I got an error in FireFox:
"VisibleList.childNodes[i].childNodes[1] is undefined"
To correct this I took the code from jerjer's answer ( i had to modify it a bit ) and came up with the following SaveLinks() method that works in FF.
function SaveLinks() {
$('#sortable1 li').each(function(i, item) {
var divs = $('div:not(.imagecontainer)', this);
var link = {
id: $(divs[0]).text(),
title: $(divs[1]).text(),
description: $(divs[2]).text(),
url: $(divs[3]).text(),
order: i + 1
};
$.post("/Home/ProcessLinks/Visible", $.toJSON(link), function(data, testStatus) {
/*This is where the user can be notified that the item was saved successfully*/
alert(link.id + " has been updated");
//window.location.reload();
}, "text");
});
$('#sortable2 li').each(function(i, item) {
var divs = $('div:not(.imagecontainer)', this);
var link = {
id: $(divs[0]).text(),
title: $(divs[1]).text(),
description: $(divs[2]).text(),
url: $(divs[3]).text(),
order: i + 1
};
$.post("/Home/ProcessLinks/Invisible", $.toJSON(link), function(data, testStatus) {
/*This is where the user can be notified that the item was saved successfully*/
alert(link.id + " has been updated");
//window.location.reload();
}, "text");
});
return false;
}
Since you are using jquery, you might as well use the jquery's shorthand for getting/setting text/html.
for instance getting text content:
link.id = $(VisibleList.childNodes[i].childNodes[1]).text();
link.title = $(VisibleList.childNodes[i].childNodes[2]).text();
link.description = $(VisibleList.childNodes[i].childNodes[3]).text();
link.url = $(VisibleList.childNodes[i].childNodes[4]).text();
link.order = i + 1;
getting html content:
link.id = $(VisibleList.childNodes[i].childNodes[1]).html();
link.title = $(VisibleList.childNodes[i].childNodes[2]).html();
link.description = $(VisibleList.childNodes[i].childNodes[3]).html();
link.url = $(VisibleList.childNodes[i].childNodes[4]).html();
link.order = i + 1;
This is the jquery equivalent:
$('#sortable1 li').each(function(){
var $li = $(this);
var link = {};
link.id = $li.children(1).text();
link.title =$li.children(2).text();
link.description = $li.children(3).text();
link.url = $li.children(4).text();
link.order = i + 1;
$.post("/Home/ProcessLinks/Visible", $.toJSON(link), function(data, testStatus) {
/*This is where the user can be notified that the item was saved successfully*/
//alert(link.id + " has been updated");
window.location.reload();
}, "text");
});

Categories