I have my app MVC Asp.net using MVVM. I am trying to bind my grid to my ViewModel but it doesn't work. This is my sample:
My ViewModel ...
var CompanyViewModel = kendo.observable({
container: null,
tabGeneral_tbx_NamelId: "tabGeneral_tbx_Name",
tabGeneral_tbx_AddresslId: "tabGeneral_tbx_Address",
tabContactPerson_tbx_namelId: "tabContactPerson_tbx_name",
tabContactPerson_tbx_lastNamelId: "tabContactPerson_tbx_lastName",
tabContactPerson_tbx_phoneNumberlId: "tabContactPerson_tbx_phoneNumber",
tabContactPerson_tbx_workStationlId: "tabContactPerson_tbx_workStation",
tabContactPerson_tbx_emaillId: "tabContactPerson_tbx_email",
name: null,
address: null,
contactPerson_name: null,
contactPerson_lastName: null,
contactPerson_phoneNumber: null,
contactPerson_workStation: null,
contactPerson_email: null,
contactPersons: new kendo.data.DataSource(),
employees: [],
init: function (container) {
this.container = container;
kendo.bind(document.body.children, this);
this.createGridContactPersons();
//this.createTextBox();
this.bindKendoUIWidgets();
},
bindKendoUIWidgets: function () {
kendo.bind($("#grid_contactPerson"), this.contactPersons);
//kendo.bind($("#" + this.tabContactPerson_tbx_namelId), this.contactPerson_name);
},
createGridContactPersons: function () {
$("#grid_contactPerson").kendoGrid({
datasource: {
//data: new kendo.data.DataSource({ data: this.contactPersons }),
schema: {
model: {
fields: {
name: { type: "string" },
lastName: { type: "string" },
phoneNumber: { type: "string" },
workStation: { type: "string" },
email: { type: "string" }
}
}
}
},
autobind: true,
columns: [{
field: "name",
title: "Nombre",
width: 150
}, {
field: "lastName",
title: "Apellidos",
width: 270
}, {
field: "phoneNumber",
title: "Teléfono",
width: 160
}, {
field: "workStation",
title: "Puesto de Trabajo",
width: 270
}, {
field: "email",
title: "Email"
}]
});
},
createTextBox: function () {
$("#" + this.tabContactPerson_tbx_namelId).kendoText();
},
click_btnAddPersonContact: function (e) {
this.get("contactPersons").add({
name: this.get("contactPerson_name"),
lastName: this.get("contactPerson_lastName"),
phoneNumber: this.get("contactPerson_phoneNumber"),
workStation: this.get("contactPerson_workStation"),
email: this.get("contactPerson_email")
});
//this.get("contactPersons").push({
// name: this.get("contactPerson_name"),
// lastName: this.get("contactPerson_lastName"),
// phoneNumber: this.get("contactPerson_phoneNumber"),
// workStation: this.get("contactPerson_workStation"),
// email: this.get("contactPerson_email")
//});
//var grid = $("#grid_contactPerson").data("kendoGrid");
//grid.dataSource.data(this.contactPersons);
//grid.dataSource.fetch();
}
My View ...
section scripts
{
<script src="~/Content/js/Company.js"></script>
<script type="text/javascript">
$(document).ready(function () {
CompanyViewModel.init();
});
</script>
}
<div class="row">
<div class="form-group">
<label for="tabContactPerson_lbl_name" class="col-sm-4 control-label">Nombre</label>
<label for="tabContactPerson_lbl_lastName" class="col-sm-8 control-label">Apellidos</label>
</div>
<div class="form-group">
<div class="col-sm-4">
Html.Kendo().TextBox().Name("tabContactPerson_tbx_name").HtmlAttributes(new { #class = "form-control100", placeholder = "Nombre", data_bind = "value: contactPerson_name" })
</div>
<div class="col-sm-8">
Html.Kendo().TextBox().Name("tabContactPerson_tbx_lastName").HtmlAttributes(new { #class = "form-control", style = "width:100%", placeholder = "Apellidos", data_bind = "value: contactPerson_lastName" })
</div>
</div>
</div>
<br />
<div class="row">
<div class="form-group">
<label for="tabContactPerson_lbl_phoneNumber" class="col-sm-4 control-label">Teléfono</label>
<label for="tabContactPerson_lbl_workStation" class="col-sm-4 control-label">Puesto de Trabajo</label>
<label for="tabContactPerson_lbl_email" class="col-sm-4 control-label">E-mail</label>
</div>
<div class="form-group">
<div class="col-sm-4">
Html.Kendo().TextBox().Name("tabContactPerson_tbx_phoneNumber").HtmlAttributes(new { #class = "form-control", style = "width:100%", placeholder = "Teléfono", data_bind = "value: contactPerson_phoneNumber" })
</div>
<div class="col-sm-4">
Html.Kendo().TextBox().Name("tabContactPerson_tbx_workStation").HtmlAttributes(new { #class = "form-control", style = "width:100%", placeholder = "Puesto de Trabajo", data_bind = "value: contactPerson_workStation" })
</div>
<div class="col-sm-4">
Html.Kendo().TextBox().Name("tabContactPerson_tbx_email").HtmlAttributes(new { #class = "form-control", style = "width:100%", placeholder = "E-mail", data_bind = "value: contactPerson_email" })
</div>
</div>
</div>
<br />
<div class="row">
<div class="form-group">
<div class="col-sm-12">
<div id="grid_contactPerson"></div>
</div>
</div>
</div>
<br />
<div class="row">
<div class="form-group">
<div class="col-sm-2">
<input data-bind="events:{ click: click_btnAddPersonContact }" type="button" id="btnAddPersonContact" value="Agregar Persona de Contacto" />
</div>
</div>
</div>
When I AddPerson the grid does not update with the data from my DataSource. How can I bind my ViewModel to the data of the grid???
Thanks
Related
I have implemented a code to create Tree View and also save it into database.
Controller
public ActionResult IndexMda()
{
using (BackendEntities context = new BackendEntities())
{
var plist = context.MDA.Where(p => p.PARENT_MDA_ID == null).Select(a => new
{
a.MDA_ID,
a.MDA_NAME,
a.MDA_DESCRIPTION,
a.ORGANIZATION_TYPE
}).ToList();
ViewBag.plist = plist;
}
GetHierarchy();
return View();
}
public JsonResult GetHierarchy()
{
List<MDA2> hdList;
List<MdaViewModel> records;
using (BackendEntities context = new BackendEntities())
{
hdList = context.MDA.ToList();
records = hdList.Where(l => l.PARENT_MDA_ID == null)
.Select(l => new MdaViewModel
{
MDA_ID = l.MDA_ID,
text = l.MDA_NAME,
MDA_DESCRIPTION = l.MDA_DESCRIPTION,
ORGANIZATION_TYPE = l.ORGANIZATION_TYPE,
PARENT_MDA_ID = l.PARENT_MDA_ID,
children = GetChildren(hdList, l.MDA_ID)
}).ToList();
}
return this.Json(records, JsonRequestBehavior.AllowGet);
// return View();
}
private List<MdaViewModel> GetChildren(List<MDA2> hdList, long PARENT_MDA_ID)
{
return hdList.Where(l => l.PARENT_MDA_ID == PARENT_MDA_ID)
.Select(l => new MdaViewModel
{
MDA_ID = l.MDA_ID,
text = l.MDA_NAME,
MDA_DESCRIPTION = l.MDA_DESCRIPTION,
ORGANIZATION_TYPE = l.ORGANIZATION_TYPE,
PARENT_MDA_ID = l.PARENT_MDA_ID,
children = GetChildren(hdList, l.MDA_ID)
}).ToList();
}
[HttpPost]
public JsonResult ChangeNodePosition(long MDA_ID, long PARENT_MDA_ID)
{
using (BackendEntities context = new BackendEntities())
{
var Hd = context.MDA.First(l => l.MDA_ID == MDA_ID);
Hd.PARENT_MDA_ID = PARENT_MDA_ID;
context.SaveChanges();
}
return this.Json(true, JsonRequestBehavior.AllowGet);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddNewNode(AddNode model)
{
try
{
if (ModelState.IsValid)
{
using (BackendEntities db = new BackendEntities())
{
MDA2 hierarchyDetail = new MDA2()
{
MDA_NAME = model.NodeName,
PARENT_MDA_ID = model.ParentName,
MDA_DESCRIPTION = model.NodeDescription,
ORGANIZATION_TYPE = model.NodeOrganizationType
};
db.MDA.Add(hierarchyDetail);
db.SaveChanges();
}
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
}
catch (Exception ex)
{
throw ex;
}
return Json(new { success = false }, JsonRequestBehavior.AllowGet);
}
The partial view is where the Tree View is created
Partial View
#model BPP.CCSP.Admin.Web.ViewModels.AddNode
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button"
class="close"
data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Add Node</h4>
</div>
<div class="modal-body">
#using (Html.BeginForm("AddNewNode", "Mda", FormMethod.Post, new { #id = "formaddNode", #class = "form-horizontal", role = "form", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="col-md-12">
<div class="col-md-6 row">
<div class="input-group">
<input type="text" class="form-control" value="Perent Node" readonly="readonly">
<span class="input-group-addon">
#Html.RadioButtonFor(model => model.NodeTypeRbtn, "Pn", new { #class = "btn btn-primary rbtnnodetype" })
</span>
</div>
</div>
<div class="col-md-6">
<div class="input-group ">
<input type="text" class="form-control" value="Child Node" readonly="readonly">
<span class="input-group-addon">
#Html.RadioButtonFor(model => model.NodeTypeRbtn, "Cn", new { #class = "rbtnnodetype" })
</span>
</div>
</div>
<br />
#Html.ValidationMessageFor(m => m.NodeTypeRbtn, "", new { #class = "alert-error" })
</div>
<div class="clearfix">
</div>
<div class="col-md-12">
<div class="petenddiv hidden">
#Html.Label("Select Parent")
#Html.DropDownList("ParentName", new SelectList(ViewBag.plist, "MDA_ID", "MDA_NAME"), "--select--", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.ParentName, "", new { #class = "alert-error" })
</div>
</div>
<div class="clearfix">
</div>
<div class="col-md-12">
<div>
#Html.Label("MDA Name")
#Html.TextBoxFor(model => model.NodeName, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.NodeName, "", new { #class = "alert-error" })
</div>
</div>
<div class="col-md-12">
<div>
#Html.Label("Description")
#Html.TextBoxFor(model => model.NodeDescription, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.NodeDescription, "", new { #class = "alert-error" })
</div>
</div>
<div class="col-md-12">
<div>
#Html.Label("Organization Type")
#Html.DropDownListFor(model => model.NodeOrganizationType, new List<SelectListItem>
{
new SelectListItem{Text = "Agency", Value = "Agency"},
new SelectListItem{Text = "Commission", Value = "Commission"},
new SelectListItem{Text = "Department", Value = "Department"},
new SelectListItem{Text = "Ministry", Value = "Ministry"}
}, "Select Error Type", new { #style = "border-radius:3px;", #type = "text", #class = "form-control", #placeholder = "Enter Organization Type", #autocomplete = "on" })
#Html.ValidationMessageFor(model => model.NodeDescription, "", new { #class = "alert-error" })
</div>
</div>
<div class="clearfix">
</div>
<br />
<br />
<div class="col-md-12">
<div>
<div class="pull-left">
<input type="submit" id="savenode" value="S A V E" class="btn btn-primary" />
</div>
<div class="pull-right">
<input type="button" id="closePopOver" value="C L O S E" class="btn btn-primary" />
</div>
</div>
</div>
<div class="clearfix">
</div>
}
</div>
</div>
View
<div class="col-md-12" style="margin:100px auto;">
<div class="modal fade in" id="modalAddNode" role="dialog" aria-hidden="true">
#Html.Partial("_AddNode")
</div>
<div class="col-md-12">
<div class="panel panel-primary">
<div class="panel-heading">Ministries, Departments and Agencies -: [ Add MDA and its Members ]</div>
<div class="panel-body">
<div id="tree"></div>
<div class="clearfix">
</div>
<br />
<div>
<button id="btnDeleteNode" data-toggle="modal" class='btn btn-danger'> Delete Node <span class="glyphicon glyphicon-trash"></span> </button>
<button id="btnpopoverAddNode" data-toggle="modal" class='btn btn-warning'> Add Node <span class="glyphicon glyphicon-plus"></span> </button>
</div>
</div>
</div>
</div>
Scipts
#section Scripts {
#System.Web.Optimization.Scripts.Render("~/bundles/jqueryval")
<script src="#Url.Content("~/Scripts/conditional-validation.js")" type="text/javascript"></script>
<script src="~/Scripts/Gijgo/gijgo.js"></script>
<link href="http://code.gijgo.com/1.3.0/css/gijgo.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
//'Hierarchy/GetHierarchy'
$(document).ready(function () {
var Usertree = "";
var tree = "";
$.ajax({
type: 'get',
dataType: 'json',
cache: false,
url: '/Mda/GetHierarchy',
success: function (records, textStatus, jqXHR) {
tree = $('#tree').tree({
primaryKey: 'MDA_ID',
dataSource: records,
dragAndDrop: true,
checkboxes: true,
iconsLibrary: 'glyphicons',
//uiLibrary: 'bootstrap'
});
Usertree = $('#Usertree').tree({
primaryKey: 'MDA_ID',
dataSource: records,
dragAndDrop: false,
checkboxes: true,
iconsLibrary: 'glyphicons',
//uiLibrary: 'bootstrap'
});
tree.on('nodeDrop', function (e, MDA_ID, PARENT_MDA_ID) {
currentNode = MDA_ID ? tree.getDataById(MDA_ID) : {};
console.log("current Node = " + currentNode);
parentNode = PerentId ? tree.getDataById(PARENT_MDA_ID) : {};
console.log("parent Node = " + parentNode);
if (currentNode.PARENT_MDA_ID === null && parentNode.PARENT_MDA_ID === null) {
alert("Parent node is not droppable..!!");
return false;
}
// console.log(parent.HierarchyLevel);
var params = { MDA_ID: MDA_ID, PARENT_MDA_ID: PARENT_MDA_ID };
$.ajax({
type: "POST",
url: "/Mda/ChangeNodePosition",
data: params,
dataType: "json",
success: function (data) {
$.ajax({
type: "Get",
url: "/Mda/GetHierarchy",
dataType: "json",
success: function (records) {
Usertree.destroy();
Usertree = $('#Usertree').tree({
primaryKey: 'MDA_ID',
dataSource: records,
dragAndDrop: false,
checkboxes: true,
iconsLibrary: 'glyphicons',
//uiLibrary: 'bootstrap'
});
}
});
}
});
});
$('#btnGetValue').click(function (e) {
var result = Usertree.getCheckedNodes();
if (result == "") { alert("Please Select Node..!!") }
else {
alert("Selected Node id is= " + result.join());
}
});
//delete node
$('#btnDeleteNode').click(function (e) {
e.preventDefault();
var result = tree.getCheckedNodes();
if (result != "") {
$.ajax({
type: "POST",
url: "/Mda/DeleteNode",
data: { values: result.toString() },
dataType: "json",
success: function (data) {
alert("Deleted successfully ");
window.location.reload();
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Error - ' + errorThrown);
},
});
}
else {
alert("Please select Node to delete..!!");
}
});
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Error - ' + errorThrown);
}
});
// show model popup to add new node in Tree
$('#btnpopoverAddNode').click(function (e) {
e.preventDefault();
$("#modalAddNode").modal("show");
});
//Save data from PopUp
$(document).on("click", "#savenode", function (event) {
event.preventDefault();
$.validator.unobtrusive.parse($('#formaddNode'));
$('#formaddNode').validate();
if ($('#formaddNode').valid()) {
var formdata = $('#formaddNode').serialize();
// alert(formdata);
$.ajax({
type: "POST",
url: "/Mda/AddNewNode",
dataType: "json",
data: formdata,
success: function (response) {
// $("#modalAddNode").modal("hide");
window.location.reload();
},
error: function (response) {
alert('Exception found');
// $("#modalAddNode").modal("hide");
window.location.reload();
},
complete: function () {
// $('.ajax-loader').css("visibility", "hidden");
}
});
}
});
//Close PopUp
$(document).on("click", "#closePopup", function (e) {
e.preventDefault();
$("#modalAddNode").modal("hide");
});
$('.rbtnnodetype').click(function (e) {
if ($(this).val() == "Pn") {
$('.petenddiv').attr("class", "petenddiv hidden");
$("#ParentName").val("");
}
else {
$('.petenddiv').attr("class", "petenddiv");
}
});
});
</script>
}
As shown above, what I have created can only do one level node. I want want to create multi-level.Whereby, a child will be a parent to other children.
Please how do I achieve this.
You can see some ASP.NET examples about this at https://github.com/atatanasov/gijgo-asp-net-examples/tree/master/Gijgo.Asp.NET.Examples
Please use our examples in order to achieve that.
Am working on a small project to get familiar with ASP.NET.
I have this model
public partial class COUNTRIES
{
public int COUNTRY_ID { get; set; }
public string COUNTRY_NAME { get; set; }
public int COUNTRY_AREA { get; set; }
}
View
<div class="col-lg-12">
<div class="form-group">
#Html.LabelFor(model => model.COUNTRY_NAME, new { #class = "col-lg-2 control-label" })
<div class="col-lg-9">
#Html.TextBoxFor(model => model.COUNTRY_NAME, new { #class = "form-control" })
</div>
</div>
</div>
<div class="col-lg-12">
<div class="form-group">
<div class="radio">
#Html.RadioButtonFor(m => m.COUNTRY_AREA, 1, new { id = "", value = "" }) North East
</div>
<div class="radio">
#Html.RadioButtonFor(m => m.COUNTRY_AREA, 2, new { id = "", value = "" }) North West
</div>
<div class="radio">
#Html.RadioButtonFor(m => m.COUNTRY_AREA, 3, new { id = "", value = "" }) South West
</div>
<div class="radio">
#Html.RadioButtonFor(m => m.COUNTRY_AREA, 4, new { id = "", value = "" }) South East
</div>
</div>
</div>
m => m.COUNTRY_AREA should generate 4 radio buttons, and the 4 radio buttons are tied to it.
What I want to achieve is that When I click on:
RadioButton 1 , it should display a popup modal form with message "You are from North East.
RadioButton 2 , it should display a popup modal form with message "You are from North West.
RadioButton 3 , it should display a popup modal form with message "You are from South East.
RadioButton 1 , it should display a popup modal form with message "You are from South East.
How do I go about it
This will work, and it is factored so that there is only one JavaScript function:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index706</title>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(function () {
$(".DoPopup").click(function (event) {
alert("You are from the " + event.target.id);
})
})
</script>
</head>
<body>
<div class="col-lg-12">
<div class="form-group">
#Html.LabelFor(model => model.COUNTRY_NAME, new { #class = "col-lg-2 control-label" })
<div class="col-lg-9">
#Html.TextBoxFor(model => model.COUNTRY_NAME, new { #class = "form-control" })
</div>
</div>
</div>
<div class="col-lg-12">
<div class="form-group">
<div class="radio">
#Html.RadioButtonFor(m => m.COUNTRY_AREA, 1, new { #class = "DoPopup", id = "North East", value = "" }) North East
</div>
<div class="radio">
#Html.RadioButtonFor(m => m.COUNTRY_AREA, 2, new { #class = "DoPopup", id = "North West", value = "" }) North West
</div>
<div class="radio">
#Html.RadioButtonFor(m => m.COUNTRY_AREA, 3, new { #class = "DoPopup", id = "South West", value = "" }) South West
</div>
<div class="radio">
#Html.RadioButtonFor(m => m.COUNTRY_AREA, 4, new { #class = "DoPopup", id = "South East", value = "" }) South East
</div>
</div>
</div>
</body>
</html>
i have jqgrid and a modal. By using the modal window we can add value to the grid
at the same time while editing on row of the grid the modal window has to be shown and populate with the row value from grid. i have tried the #htmlaction click on the jqgrid it goes to the controller it ok but how can call the modal window to populate the grid row data while on editing.
jQuery("#listvalues_ajaxGrid").jqGrid({
url: '#Url.Action("ListvaluesGrid")',
datatype: "json",
mtype: 'Get',
colNames: [
'List Key', 'List Value Name', 'List Value Code', 'Inactive'],
colModel: [
{ key: false, name: 'list_key', hidden: true },
{
key: false, name: 'list_value_name',
formatter: function (cellvalue, options, rowObject) {
show();
var x = '#Html.ActionLink("Col", "Edit", "Lists", new { id = "listvalid" }, new { #style = "color:black;font-weight:bold;" })';
return x.replace("listvalid", rowObject.list_key).replace("Col", rowObject.list_value_name);
}, sortable: true, align: 'left', width: 200, editable: true
},
#*#Html.ActionLink("Edit", "Edit", null, new { id = 234 }, new { #class = "modal" })*#
//{ key: true, name: 'list_value_name', hidden: false, editable:true },
{ key: false, name: 'list_value_code', hidden: false, editable: false },
{ key: false, name: 'inactive', hidden: false, width: 50, sortable: false, formatter: "checkbox", align: "center", editable: false },
],
sortname: 'list_key',
sortorder: "asc",
viewrecords: true,
rowNum: 5,
pager: '#listvalues_ajaxPager',
onSelectRow: function (id) {
if (id && id !== lastSel) {
listvalues_ajaxGrid.jqGrid('restoreRow', lastSel);
var cm = grid.jqGrid('getColProp', 'Name');
cm.editable = false;
grid.jqGrid('editRow', id, true, null, null, 'clientArray');
cm.editable = true;
lastSel = id;
}
},
height: '200px', mtype: 'GET',
emptyrecords: 'No records found',
autowidth: true,
mutiselect: true,
altRows: true,
'cellEdit': true,
'cellsubmit': 'clientArray',
editurl: '#Url.Action("ListvaluesGrid")',
loadComplete: function () {
var table = this;
setTimeout(function () {
updatePagerIcons(table);
}, 0);
},
jsonReader: {
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
userdata: "userdata"
},
//editurl:
});
my bootstrap modal window
<div class="modal fade" id="modalBootstrap" role="dialog">
#Html.Hidden("hid_listvalues")
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">List Values</h4>
</div>
<div class="modal-body">
<div class="form-group">
#Html.LabelFor(model => model.maslistvalues.list_value_code, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.maslistvalues.list_value_code, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.maslistvalues.list_value_code, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.maslistvalues.list_value_name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.maslistvalues.list_value_name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.maslistvalues.list_value_name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.maslistvalues.inactive, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.maslistvalues.inactive)
#Html.ValidationMessageFor(model => model.maslistvalues.inactive, "", new { #class = "text-danger" })
</div>
</div>
</div>
</div>
<div class="modal-footer">
<div class="wizard-actions">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<input type="submit" value="Save" class="btn btn-primary" onclick="saveclick_listvalues();" />
</div>
</div>
</div>
</div>
</div>
In the jquery formatter function we can call the modal popup
formatter: function (cellvalue, options, rowObject) {
var x ='#Html.ActionLink("Col", "Index", "Lists", new { id1 = "listid" }, new { #style = "color:black;font-weight:bold;", onclick="check();" })';
//var x+='<i class="fa fa-pencil icon"></i>';
var a = sessionStorage["Selected"];
if (a == 0)
{
$('#modalBootstrap').modal('show'); //---popupshow
sessionStorage["Selected"] = null;
}
return x.replace("listid", rowObject.list_value_key).replace("Col", rowObject.list_value_name);
}, sortable: false, align: 'left', editable: false
I am building a SPA per the guidance provided in John Papa's Jumpstart.
When I create the model, it has
modelObservable().entityAspect.entityState.isAdded() = true;
I update the text, dropdown and
modelObservable().entityAspect.entityState.isAdded() = false;
in my Datacontext:
var createProject = function (position) {
return manager.createEntity(entityNames.project,
{
positionId : position.id(),
start : position.start(),
memberId : position.memberId()
});
};
which is called from my add viewModel:
define(['services/datacontext', 'durandal/plugins/router', 'durandal/system', 'durandal/app', 'services/logger', 'services/uiService'],
function (datacontext, router, system, app, logger, ui) {
var model = ko.observable();
var position = ko.observable();
var hourTypes = ko.observableArray([]);
var isSaving = ko.observable(false);
// init
var activate = function (routeData) {
logger.log('Add View Activated', null, 'add', true);
var positionId = parseInt(routeData.id);
initLookups();
return datacontext.getPositionById(positionId, position).then(**createProject**);
};
var initLookups = function () {
logger.log('initLookups', null, 'add', true);
hourTypes(datacontext.lookups.hourTypes);
};
// state
**var createProject = function () {
return model(datacontext.createProject(position()));
}**
var addNewProject = function () {
if (position == undefined || position().id() < 1) {
console.log('callback addNewProject');
setTimeout(function () {
addNewProject();
}, 1000);
} else {
datacontext.addProject(position(), model);
console.log(model().id());
return;
}
}
var **save** = function () {
isSaving(true);
**datacontext.saveChanges()**
.then(goToEditView).fin(complete);
function complete() {
isSaving(false);
}
function goToEditView() {
isSaving(false);
var url = '#/Projects/';
router.navigateTo(url + model().id());
}
};
var vm = {
activate: activate,
hourTypes: hourTypes,
isAdded: isAdded,
model: model,
save: save,
title: 'Details View'
};
return vm;
});
the html
<section data-bind="with:model">
<h1 data-bind="text: name"> <i class="icon-asterisk" data-bind="visible: hasChanges" style="font-size: 30px;"></i></h1>
<div class="errorPanel"></div>
<div id="overview" class="project" >
<div class="row">
<div class="span4">
<label class="requiredLabel">Name*</label>
<input type="text" name="name" data-bind="value: name" style="width: 27em;" class="required" placeholder="Project Name" required validationMessage="Project Name required" /><span class="k-invalid-msg" data-for="title"></span>
</div>
</div>
<div class="row">
<div class="span3"><label class="requiredLabel">Start*</label></div>
<div class="span3"><label class="requiredLabel">End</label></div>
</div>
<div class="row">
<div class="span3"><input name="start" data-bind="shortDate: start" class="date required" required="required" placeholder="mm/dd/yyyy" style=" width:142px"></div>
<div class="span3"><input name="end" data-bind="shortDate: end" class="date" placeholder="mm/dd/yyyy" style=" width:142px"><span class="k-invalid-msg" data-for="end"></span></div>
</div>
<br/>
<div class="row">
<div class="span3"><label for="hourType" class="requiredLabel">Measure As*</label></div>
<div class="span2"><label for="hoursPerWeek" class="requiredLabel">Hours/Week</label></div>
<div class="span2"><label for="totalHours" class="requiredLabel">Total Hours</label></div>
</div>
<div class="row">
<div class="span3">
<select id="hourType" data-bind="options: $parent.hourTypes, optionsText: 'name', value: hourType" required validationMessage="Measure As required"></select><span class="k-invalid-msg" data-for="hourType"></span>
</div>
<div class="span2">
<input name="hoursPerWeek" type="number" min="1" max="120" required="required" data-bind="value: hoursPerWeek, validationOptions: { errorElementClass: 'input-validation-error' }, enable: hourType().id() == 1" class="hours required"" style="width: 80px;" validationMessage="Hours required"><span class="k-invalid-msg" data-for="projectHours"></span>
<span class="k-invalid-msg" data-for="totalHours"></span>
</div>
<div class="span2">
<input name="totalHours" type="number" min="40" max="2080" required="required" data-bind="value: totalHours, validationOptions: { errorElementClass: 'input-validation-error' }, enable: hourType().id() == 2" class="hours required"" style="width: 80px;" validationMessage="Hours required"><span class="k-invalid-msg" data-for="projectHours"></span>
<span class="k-invalid-msg" data-for="totalHours"></span>
</div>
</div>
<div class="row">
<div class="span4">
<label class="requiredLabel">Description*</label><span class="k-invalid-msg" data-for="description"></span><span id="posMinDesc" style="visibility:hidden"></span>
<textarea id="description" name="description" style="height: 200px; width: 650px;" data-bind="value: description, enabled:true, click: $parent.clearDefaults" rows="4" cols="60" class="richTextEditor k-textbox" required validationMessage="Description required" ></textarea>
</div>
</div>
</div>
<div class="button-bar">
<button class="btn btn-info" data-bind="click: $parent.goBack"><i class="icon-hand-left"></i> Back</button>
<button class="btn btn-info" data-bind="click: $parent.save, enable: $parent.canSave"><i class="icon-save"></i> Save</button>
</div>
</section>
The json breeze sends to my controller is this:
{
"entities": [
{
"Id": -1,
"Description": "poi",
"End": null,
"Gauge": 0,
"Score": 0,
"HourTypeId": 1,
"HoursPerWeek": 45,
"HourlyRate": null,
"TotalHours": null,
"WeightedHours": 0,
"CreditMinutes": 0,
"TotalCompensation": null,
"IsCurrent": false,
"Name": "poi",
"PositionId": 1,
"MemberId": 1,
"Start": "2011-09-01T00:00:00Z",
"undefined": false,
"entityAspect": {
"entityTypeName": "Project:#SkillTraxx.Model",
"defaultResourceName": "Projects",
"entityState": "Modified",
"originalValuesMap": {
"Name": "",
"HourTypeId": 0,
"HoursPerWeek": null,
"Description": ""
},
"autoGeneratedKey": {
"propertyName": "Id",
"autoGeneratedKeyType": "Identity"
}
}
}
],
"saveOptions": {}
}
As you can see, the above is incorrect b/c state is "Modified" and the Id = -1. This throws an error server side. I suppose I could trap the DbUpdateConcurrencyException, unwind the JObject and change "Modified" to added, but that's got code smell all over it.
If anyone can help me find the face-palm moment in all of this, I'm ready.
Thanks for looking!
FACE PALMED IT
I took Jays advice and started stripping away the html then I realize it was my handler.
The update method on shortDate handler was responsible. I wrapped it in an if statement not to send the update if the current state is added.
ko.bindingHandlers.shortDate = {
init: function (element, valueAccessor) {
//attach an event handler to our dom element to handle user input
element.onchange = function () {
var value = valueAccessor();//get our observable
//set our observable to the parsed date from the input
value(moment(element.value).toDate());
};
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var value = valueAccessor();
var valueUnwrapped = ko.utils.unwrapObservable(value);
if (valueUnwrapped) {
element.value = moment(valueUnwrapped).format('L');
if (!viewModel.entityAspect.entityState.isAdded())
{
**viewModel.entityAspect.setModified();**
}
}
}
};
This is what is getting sent to the server:
http://localhost:3182/Admin/UserAdmin/Save?Count=0&Keys=System.Collections.Generic.Dictionary%602%2BKeyCollection%5BSystem.String%2CSystem.Object%5D&Values=System.Collections.Generic.Dictionary%602%2BValueCollection%5BSystem.String%2CSystem.Object%5D
I am using the unobtrusive jquery.unobtrusive-ajax and it is working fine on other pages in my project. I am not doing anything fancy with the BeginForm helper. It is pretty straight forward actually. I can post it if it helps, but there is not much too it.
I thought another library might be interfering with my code so I removed other scripts and it still does the same thing. It is very weird. Has anyone seen this before and know how to fix it?
Here is the entire view:
#using YogaDiVita.Ui.Helpers
#model YogaDiVita.Domain.YogaDiVitaContext.Model.User
#{
ViewBag.Title = "Profile";
Layout = "~/Areas/Admin/Views/Shared/_AdminLayout.cshtml";
var isInstructor = (bool)ViewBag.IsInstructor;
}
<link href="#Url.ContentArea("~/Scripts/plugins/fineUploader/fineuploader.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Scripts/plugins/jCrop/css/jquery.Jcrop.min.css")" rel="stylesheet"
type="text/css" />
<div class="row-fluid">
<div class="span12">
<h3 class="heading">User Profile</h3>
<div class="row-fluid">
<div class="span8">
#using (Ajax.BeginForm("Save",new RouteValueDictionary(), new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "OnSuccess",
OnFailure = "OnFailure"
}, new { #class = "form-horizontal well" }))
{
#Html.HiddenFor(u => u.Id)
#Html.HiddenFor(u => u.CreatedById)
#Html.HiddenFor(u => u.ModifiedById)
#Html.HiddenFor(u => u.Username)
#Html.Hidden("isInstructor", isInstructor)
<fieldset>
<div class="control-group formSep">
<label class="control-label">
Username</label>
<div class="controls text_line">
<strong>#Model.Username</strong> Reset Password
</div>
</div>
<div class="control-group formSep">
<label for="fileinput" class="control-label">
User avatar</label>
<div class="controls">
<div data-fileupload="image" class="fileupload fileupload-new">
<div style="width: 80px; height: 80px;" class="fileupload-new thumbnail">
<img src="http://www.placehold.it/108x108/EFEFEF/AAAAAA " alt="" id="userAvatar">
</div>
<a href="/Admin/UserAdmin/ImageUpload/#Model.Id" class="btn avatarUpload">Upload New
Image</a>
</div>
</div>
</div>
<div class="control-group formSep">
<label for="FirstName" class="control-label">
First Name</label>
<div class="controls">
#Html.TextBoxFor(u => u.FirstName, new { #class = "input-xlarge" })
</div>
</div>
<div class="control-group formSep">
<label for="FirstName" class="control-label">
Last Name</label>
<div class="controls">
#Html.TextBoxFor(u => u.LastName, new { #class = "input-xlarge" })
</div>
</div>
<div class="control-group formSep">
<label for="u_email" class="control-label">
Email Address</label>
<div class="controls">
#Html.TextBoxFor(u => u.EmailAddress, new { #class = "input-xlarge" })
</div>
</div>
<div class="control-group formSep">
<label for="u_email" class="control-label">
Telephone Number</label>
<div class="controls">
#Html.TextBoxFor(u => u.TelephoneNumber, new { #class = "input-xlarge" })
</div>
</div>
<div class="control-group formSep">
<label for="u_email" class="control-label">
Mobile Number</label>
<div class="controls">
#Html.TextBoxFor(u => u.MobileTelephoneNumber, new { #class = "input-xlarge" })
</div>
</div>
<div class="control-group formSep">
<label for="u_email" class="control-label">
Mobile Number</label>
<div class="controls">
#Html.TextBoxFor(u => u.MobileTelephoneNumber, new { #class = "input-xlarge" })
</div>
</div>
<div class="control-group formSep">
<label for="u_email" class="control-label">
Is Instructor</label>
<div class="controls">
#Html.CheckBox("cbIsInstructor", isInstructor)
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-gebo" type="submit">
Save changes</button>
</div>
</div>
</fieldset>
}
</div>
</div>
</div>
</div>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.9/jquery.validate.js"
type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/plugins/jcrop/jquery.Jcrop.min.js")" type="text/javascript"></script>
<script src="#Url.ContentArea("~/Scripts/plugins/fineUploader/util.js")"></script>
<script src="#Url.ContentArea("~/Scripts/plugins/fineUploader/button.js")"></script>
<script src="#Url.ContentArea("~/Scripts/plugins/fineUploader/handler.base.js")"></script>
<script src="#Url.ContentArea("~/Scripts/plugins/fineUploader/handler.form.js")"></script>
<script src="#Url.ContentArea("~/Scripts/plugins/fineUploader/handler.xhr.js")"></script>
<script src="#Url.ContentArea("~/Scripts/plugins/fineUploader/uploader.basic.js")"></script>
<script src="#Url.ContentArea("~/Scripts/plugins/fineUploader/dnd.js")"></script>
<script src="#Url.ContentArea("~/Scripts/plugins/fineUploader/uploader.js")"></script>
<script src="#Url.ContentArea("~/Scripts/plugins/fineUploader/jquery-plugin.js")"></script>
<script>
$(function () {
loadUserAvatar();
$('.avatarUpload').colorbox({
initialHeight: '520',
initialWidth: '650',
iframe: false,
opacity: 0.45,
onClosed: function () {
loadUserAvatar();
}
});
$('.resetPasswordWindow').colorbox({
initialHeight: '0',
initialWidth: '0',
iframe: false,
opacity: 0.45,
onClosed: function () {
},
onComplete: function () {
$.validator.addMethod("passwordsMustMatch", function (value, element) {
return $('#validatePassword').val() == $('#password').val();
}, "The passwords do not match");
$('.resetPasswordForm').validate({
onkeyup: false,
errorClass: 'error',
validClass: 'valid',
errorPlacement: function (error, element) {
error.appendTo(element.closest("div.controls"));
},
highlight: function (element) {
$(element).closest("div.control-group").addClass("error f_error");
var thisStep = $(element).closest('form').prev('ul').find('.current-step');
thisStep.addClass('error-image');
},
unhighlight: function (element) {
$(element).closest("div.control-group").removeClass("error f_error");
if (!$(element).closest('form').find('div.error').length) {
var thisStep = $(element).closest('form').prev('ul').find('.current-step');
thisStep.removeClass('error-image');
};
},
rules: {
password: { required: true, minlength: 6, passwordsMustMatch: true },
validatePassword: { required: true, minlength: 6, passwordsMustMatch: true }
},
invalidHandler: function (form, validator) {
$.sticky("There are some errors. Please corect them and submit again.", { autoclose: 5000, position: "top-right", type: "st-error" });
}
});
}
});
});
function loadUserAvatar(parameters) {
$.ajax({
url: '/Admin/Avatar/AvatarLoad/#Model.Id',
type: 'POST',
cache: false,
timeout: 100000,
error: function (xhr, status, error) {
alert(error + " " + status);
},
success: function (data) {
$("#userAvatar").attr("src", data.Image.ThumbNailRelativePath);
}
});
}
function OnSuccess(parameters) {
$.sticky("The user profile has been updated successfully.", { autoclose: 5000, position: "top-right", type: "st-error" });
}
function OnFailure(parameters) {
$.sticky("There was an error saving the profile. </br>" + parameters.message, { autoclose: 5000, position: "top-right", type: "st-error" });
}
</script>
UPDATE:
After a little research at what as happening, I was getting this error after the post: An item with the same key has already been added
You can't bind directly to Collections - see ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries for examples of how to accomlish what you are trying to do.
Well, i figured out the issue. Kind of silly really. The issue was I had an interface on my Model. There were 2 version of the property Username. One was named UserName (with a capital N) and the other was Username (lowercase n). This blog post helped.