I am attempting to using knockout to create a client side model so client side validation can be done on the needed attributes, some of which are nested and or in nested lists of other models.
In following some guides and patterns, I have tried to map a test list from the main view model and send it back to the controller when the form submits, with validation that would prevent the form from being submitted if the value is null.
When the form is submitted, not only does it fail to validate with the current set up, the edited values (which are correctly populated in the view on load, so some type of binding is correctly working) return as null in the controller.
namespace KnockoutDemo.Models
{
public class XmlParameter
{
public HttpPostedFileBase XmlValue;
public string Name;
}
}
public class TestStepViewModel
{
public int TestStepId { get; set; }
public string TestStepName { get; set; }
public string Message { get; set; }
public List<XmlParameter> XmlParameters { get; set; }
}
View
#using System.Web.Mvc.Ajax
#using System.Activities.Expressions
#using System.Web.Script.Serialization
#model KnockoutDemo.Models.TestStepViewModel
#{ string data = new JavaScriptSerializer().Serialize(Model);}
#section scripts
{
<script src="~/Scripts/knockout-3.4.0.js"></script>
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/teststepviewmodel.js"></script>
<script type="text/javascript">
var testStepViewModel = new TestStepViewModel(#Html.Raw(data));
ko.applyBindings(testStepViewModel);
</script>
}
<form>
<div>
<div class="form-group">
<label class="control-label" for="TestStepName">Test Step Name:</label>
<input class="form-control" name="TestStepName" id="TestStepName" data-bind="value: TestStepName"/>
</div>
<div class="form-group">
<label class="control-label" for="TestStepName">Test Step Id:</label>
<input class="form-control" name="TestStepId" id="TestStepId" data-bind="value: TestStepId" disabled="disabled"/>
</div>
<table class="table table-striped">
<tr>
<th>Product Code</th>
</tr>
<tbody data-bind="foreach: XmlParameters">
<tr>
<td class="form-group"><input name="Name" class="form-control input-sm" data-bind="attr: {'id': 'Name_' + $index()}, value: Name"/></td>
</tr>
</tbody>
</table>
</div>
<p><button class="btn btn-primary" data-bind="click: save" type="submit" >Save</button></p>
</form>
teststepviewmodel.js + validation
TestStepViewModel = function(data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
self.save = function () {
$.ajax({
url: "/Home/Save/",
type: "POST",
data: ko.toJSON(self),
contentType: "application/json"
});
}
}
var XmlParameter = function(data) {
var self = this;
ko.mapping.fromJS(data, mapping, self);
}
var mapping = {
'XmlParameters': {
key: function (xmlParameters) {
return ko.utils.unwrapObservable(xmlParameters.Name);
},
create: function (options) {
return new XmlParameter(options.data);
}
}
};
$("form").validate({
submithandler: function () {
testStepViewModel.save();
},
rules: {
TestStepName: {
required: true,
maxlength: 30
},
Value: {
required: true
},
XmlValue: {
required: true
}
},
messages: {
TestStepName: {
required: "A Test Step must have a non-null value, please enter a name"
},
Value: {
required: "The parameter can't be null/empty"
}
}
});
The JsonResult Save() controller correctly populates the Id and Test Step Name, however the XmlParameters are both null.
Controllers (Like I said, this is simply a test to return knockout model with client side validation, so I'm simply populating a view model on load and setting a breakpoint on the JsonResult to see the contents of the model)
public ActionResult Index(TestStepViewModel ts)
{
TestStepViewModel testStepViewModel = new TestStepViewModel
{
TestStepName = "Editing A Test Step",
TestStepId = 10,
Message = "Hello, this is a message"
};
testStepViewModel.XmlParameters = new List<XmlParameter>();
testStepViewModel.XmlParameters.Add(new XmlParameter
{
Name = "Xml P1"
});
testStepViewModel.XmlParameters.Add(new XmlParameter
{
Name = "Xml P2"
});
return View("Index", testStepViewModel);
}
public JsonResult Save(TestStepViewModel testStepViewModel)
{
return null;
}
Related
I am trying to store the employeeIds from the selected row of the table into the model column EmployeeReinstateVM.selectedEmployeeId from the click event of 'btnUpdate', each id must be stored to EmployeeReinstateVM.selectedEmployeeId. Currently the Ids are stored in to selectedEmployeeId hidden column as array string "23,24,25" So I am trying to store each employee id of the selected rows into the EmployeeReinstateVM.selectedEmployeeId from javascript to send the model into controller post method with selected employeeIds. I am looking for the help from someone. Here is the code
Model Class
public class EmployeeReinstateVM
{
public int EmployeeID { get; set; }
public string EmployeeName { get; set; }
public List<string> selectedEmployeeId { get; set; }
public IEnumerable<EmployeeModel> employees { get; set; }
}
Views
<style>
.selectable-row.selected {
background-color: #ddd;
}
</style>
#model EmployeeReinstateVM
foreach (var item in Model.employees)
{
<tr class="selectable-row
#(Model.selectedEmployeeId.Contains(item.EmployeeID.ToString()) ? "selected" :"")"
employee-id="#item.EmployeeID">
<td>#item.EmployeeID</td>
<td>#item.EmployeeName</td>
</tr>
}
<input hidden id="selectedEmployeeId" asp-for="selectedEmployeeId" name="selectedEmployeeId" value="">
<button type="submit" class="btn btn-primary form-control" id="btnUpdate" name="btnActivate" value="update">
Update
</button>
<script type="text/javascript">
$(document).ready(function() {
var employeeIds = [];
$(".selectable-row").click(function() {
$(this).toggleClass("selected");
var employeeId = $(this).attr('employee-id');
if ($(this).hasClass("selected")) {
employeeIds.push(employeeId);
//employeeIds.push($(this).attr('employee-id'));
} else {
employeeIds = employeeIds.filter(function(id) {
return id !== employeeId;
});
}
});
$("#btnUpdate").click(function() {
$("#selectedEmployeeId").val(employeeIds);
console.log($("#selectedEmployeeId").val());
});
})
This seems to be simpler - you need to store the result
$(".selectable-row").click(function() {
$(this).toggleClass("selected");
$("#selectedEmployeeId")
.val(
$("tr[employee-id].selected")
.map(function() { return $(this).attr("employee-id") })
.get()
.join(",")
);
});
store each employee id of the selected rows into the
EmployeeReinstateVM.selectedEmployeeId from javascript to send the
model into controller post method with selected employeeIds
Do you want to try the below code?
$("#btnSave").click(function () {
$("#selectedEmployeeId").val(employeeIds);
console.log($("#selectedEmployeeId").val());
$.ajax({
type: "POST",
url: "/Keepselected/ReinstateEmployee",
data: { "selectedEmployeeId": employeeIds },
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function (response) {
alert(response);
}
});
});
result:
my java code is not working when pulling data in database.
Where am I going wrong? I tried many times but it didn't work.
I'm looking at debug mode mastercontroller. data is not coming.
I have jquery.min.js attached on my layout page.
I tried another js code as a trial, it works. I'm waiting for your help
My java code is not working when adding category array to mvc using jquery
//categoryaddt.js
$(document).ready(function () {
$("#categoryform").validate({
rules: {
Name: { required: true },
},
messages: {
Nanem: "Please Enter a Valid Name."
},
submitHandler: function (e) {
var chk = 0;
if ($("#closeButton").prop('checked') == true) {
chk = 1;
}
var RequestCls = {
Name: $("#txtName").val(),
Active: chk
}
var UrlApi = '#Url.Content("~")' + "Master/AddCategory";
$.ajax({
url: UrlApi,
type: 'POST',
data: JSON.stringify(RequestCls),
contentType: 'application/json; charset=utf-8',
success: function (data) {
alert(data.message);
},
error: function (data) {
alert(data.message);
}
});
}
})
});
//Category.cshtml
#{
ViewBag.Title = "Category";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row">
<div class="row">
<div class="card">
<div class="card-body">
<form id="categoryform" method="post">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="Name">Name</label>
<input id="txtName" name="Name" type="text" class="form-control" autocomplete="off" />
</div>
<div class="custom-control custum-checkbox mb-2">
<input type="checkbox" class="custom-control-input input-mini" id="closeButton" value="checked" />
<label class="custom-control-label" for="closeButton">Is Active</label>
</div>
</div>
</div>
<button type="submit" id="btnSave" class="btn btn-primary mr-1 waves-effect waves-light"></button>
</form>
</div>
</div>
</div>
</div>
#section scripts{
<script src="~/Scripts/categoryaddt.js"></script>
}
//MasterCls.cs
using Nero_Medya_Inventory_Management_System.BusinessLogic.IService;
using Nero_Medya_Inventory_Management_System.Utility.RequestCls;
using Nero_Medya_Inventory_Management_System.Utility.Responsecls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Nero_Medya_Inventory_Management_System.BusinessLogic.ServiceCls
{
public class MasterCls : IMaster
{
QrperidEntities dbEntity;
public MasterCls()
{
dbEntity = new QrperidEntities();
}
public ResponseCls AddCategory(RequestCls obj)
{
ResponseCls result = new ResponseCls();
result.message = "Kayıt Başarı ile Yapıldı...!";
result.status = "succes";
result.flag = 1;
try
{
using (var db = dbEntity)
{
Category _category = new Category();
_category.Name = obj.Name;
_category.Active = obj.Active;
db.Category.Add(_category);
db.SaveChanges();
}
}
catch (Exception ex)
{
result.message = ex.Message.ToString();
result.status = "error";
result.flag = 0;
}
return result;
}
}
}
//IMaster.cs
using Nero_Medya_Inventory_Management_System.Utility.RequestCls;
using Nero_Medya_Inventory_Management_System.Utility.Responsecls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Nero_Medya_Inventory_Management_System.BusinessLogic.IService
{
public interface IMaster
{
ResponseCls AddCategory( RequestCls obj );
}
}
//Category.cs
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Nero_Medya_Inventory_Management_System
{
using System;
using System.Collections.Generic;
public partial class Category
{
public int Id { get; set; }
public string Name { get; set; }
public Nullable<int> Active { get; set; }
}
}
//MasterController.cs
using Nero_Medya_Inventory_Management_System.BusinessLogic.IService;
using Nero_Medya_Inventory_Management_System.BusinessLogic.ServiceCls;
using Nero_Medya_Inventory_Management_System.Utility.RequestCls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Nero_Medya_Inventory_Management_System.Controllers
{
public class MasterController : Controller
{
// GET: Master
IMaster _master;
public MasterController()
{
_master = new MasterCls();
}
public ActionResult Category()
{
return View();
}
[HttpPost]
public JsonResult AddCategory(RequestCls obj)
{
var result = _master.AddCategory(obj);
return Json(result,JsonRequestBehavior.AllowGet);
}
}
}
Login.cshtml
<script type="text/javascript">
function data() {
var n = document.getElementById("username").value;
var m = document.getElementById("password").value;
?
</script>
<button type="submit"class="btn-login" onClick="Data()">
Giriş Yap </button>
Account Controller
DBEntities dB = new DBEntities();
[HttpPost] (username) (password)
public ActionResult Login(string KullaniciAdi,string Sifre)
{
// Session[KullaniciAdi] = dB.Profil.Where(x => x.KullaniciAdi == KullaniciAdi && x.Sifre == Sifre).FirstOrDefault();
var session = (from p in dB.Profil
where p.KullaniciAdi == KullaniciAdi
select p).FirstOrDefault();
return View();
}
My OOP homework is this website and i want to create a login with sending password and username to controller and compare submitted data and the data in the database .Please help :)
You can send client data by using ajax request,
this is your inputs
<input id="username" type="text" />
<input id="password" type="password" />
<input id="loginbutton" onclick="UserLogin()" type="submit" value="Submit" />
Submit button bind with UserLogin js function.
here is the js function. we are sending ajax post request here to our controller
<script type="text/javascript">
function UserLogin() {
var n = document.getElementById("username").value;
var p = document.getElementById("password").value;
var postObj = JSON.stringify({
"username": n,
"password": p
});
$.ajax({
url: "/Home/Login", // endpoint
type: "POST",
data: postObj,
contentType: "application/json; charset=utf-8",
success: function (result) {
// success
},
error: function (errorData) { onError(errorData); }
});
}
</script>
And your controller should be like, you can implement login logic inside of the method.
[HttpPost]
public ActionResult Login(string username, string password)
{
// use your code loged in
return Json(true, JsonRequestBehavior.AllowGet);
}
First You Create a Class :
public class LoginModel
{
[Required(ErrorMessage = "User Name can not be empty!")]
public string LOGINID { get; set; }
[Required(ErrorMessage = "Password can not be empty!")]
public string LOGINPW { get; set; }
}
Then Your Controller Action Method do this:
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(LoginModel model)
{
//Here check the Login Id and Password
return View();
}
Now in view Write this. Now when you click the submit button a post call go to the Login Controller with given LOGINID and LOGINPW :
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<!-- login screen -->
<form action="#">
#Html.TextBoxFor(m => m.LOGINID, htmlAttributes: new { #class = "form-control", placeholder = "Login ID" })
#Html.ValidationMessageFor(model => model.LOGINID, "", new { #class = "text-danger", style = "float: left" })
#Html.PasswordFor(m => m.LOGINPW, htmlAttributes: new { #class = "form-control", placeholder = "Password" })
#Html.ValidationMessageFor(model => model.LOGINPW, "", new { #class = "text-danger", style = "float: left" })
<button type="submit" class="btn btn-primary" style="background: #2e6da4; color: #FFF;">Login</button>
</form>
}
#{
var actionURL = Url.Action("Action", "Controller",
FormMethod.Post, Request.Url.Scheme)
+ Request.Url.PathAndQuery;
}
#using (Html.BeginForm("Action", "Controller", FormMethod.Post,
new { #action = actionURL }))
{
<input type="text" name="username">
<input type="text" name="password">
<button type="submit"class="btn-login"></button>
}//Then use Request.Form[0] with the id to get the user name and password in the controller action.
I have a complex object that I need to pass to the controller when submitting a form. This complex object has an object and a list of objects. This is my Web API controller that receives the complex object via post with ajax:
[HttpPost]
public IHttpActionResult CreatePurchaseInvoice(NewPurchaseInvoice newPurchaseInvoice)
{
try
{
var purchaseInvoice = new PurchaseInvoice
{
Id = newPurchaseInvoice.PurchaseInvoice.Id,
DatePurchaseInvoice = newPurchaseInvoice.PurchaseInvoice.DatePurchaseInvoice
};
// Here i do other stuff with the list of objects
_context.SaveChanges();
}
catch(Exception ex)
{
return BadRequest();
}
return Ok();
}
This is my html form:
<form id="purchaseInvoiceForm">
<div class="row">
<div class="col-lg-6">
<label>Order:</label>
<select id="numberOrder" class="form-control" required name="numberOrder">
<option value="">Select an order number...</option>
</select>
</div>
<div class="col-lg-6">
<div class="form-group">
<label>Date of Purchase Invoice:</label><br />
<input id="datePurchaseInvoice" style="width: 70%" />
</div>
</div>
</div>
//Here i have an html table and every row i push into an array of the complex object
</form>
And this is my jQuery code where i send the complex object via ajax:
$(document).ready(function(){
//this is the declaration of my complex object
var newPurchaseInvoice = {
PurchaseInvoice: {},
PurchaseInvoiceDetails: []
}
$("#purchaseInvoiceForm").submit(function (e) {
e.preventDefault();
newPurchaseInvoice.PurchaseInvoice= {
Id: $("#numberOrder").val(),
DatePurchaseInvoice : $("#datePurchaseInvoice").val()
}
$.ajax({
url: "/api/purchaseInvoices",
method: "post",
data: newPurchaseInvoice
});
});
});
The problem I have is that the date of the KendoDateTimePicker is not sending correctly to the controller.
I get this date and not the one I select with the kendoDateTimePicker. This is the DatePurchaseInvoice property of my PurchaseInvoice model in spanish:
This is my KendoDateTimePicker for jQuery:
$("#datePurchaseInvoice").kendoDateTimePicker({
value: new Date(),
dateInput: true
});
And this is my NewPurchaseInvoice model:
public class public class NewPurchaseInvoice
{
public PurchaseInvoice PurchaseInvoice{ get; set; }
public List<PurchaseInvoiceDetail> PurchaseInvoiceDetails{ get; set; }
}
This is my PurchaseInvoice model:
public class PurchaseInvoice
{
public int Id { get; set; }
public DateTime DatePurchaseInvoice { get; set; }
}
You need to be specifying the type of data you are supplying:
contentType: 'application/json'
And possibly dataType too depending on your response type. And according to this post, you may need to stringify your response. I don't think I've needed to do that but I don't often use AJAX operations for complicated data types.
To preface this question, I will admit that I know nothing about javascript and related topics. I am trying to have a table be created and filled out based on a button push. If I pass the data directly into the ViewModel, it displays correctly, so I know the table is working right. Here is the JQuery request:
<input type="button" id="RootsBtn" value="Go"/>
<script language="javascript" type="text/javascript">
$(function () {
$("#RootsBtn").click(function () {
$.ajax({
cache: false,
type: "GET",
url: "#(Url.RouteUrl("GetApplications"))",
data: {},
success: function (data) {
alert(data.length);
$('#AppTableID').show();
},
error: function (xhr, ajaxOptions, throwError) {
alert("Error");
$('#AppTableID').hide();
}
});
});
});
</script>
I'm basing this code loosely on code I'm using to populate a dropdown list. I know the data is being grabbed properly because the alert(data.length); line shows the proper number of objects in my list.
The dropdown code included a $.each line. I have tried using variants of this and nothing has worked for me.
How would I get the data saved into my ViewModel so that it can be displayed?
EDIT: Adding more details
This is the Table display in my view:
<div id="AppTableID">
<table id="dashboard">
<thead>
<th>
#Html.LabelFor(model => model.apps.FirstOrDefault().AppStringID)
</th>
<th>
#Html.LabelFor(model => model.apps.FirstOrDefault().ApplicationCategoryID)
</th>
<th>
#Html.LabelFor(model => model.apps.FirstOrDefault().Description)
</th>
</thead>
#foreach (var item in Model.apps ?? new List<Application> { null })
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.AppStringID)
</td>
<td>
#Html.DisplayFor(modelItem => item.ApplicationCategoryID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
</table>
</div>
This is my viewmodel which is passed into the view:
public class HomeViewModel
{
public HomeViewModel()
{
apps = new List<Application>();
}
public IEnumerable<Application> apps { get; set; }
}
This is the Application class:
public class Application
{
public long ID { get; set; }
public string AppStringID { get; set; }
public int? ApplicationCategoryID { get; set; }
public string Description { get; set; }
}
This is GetApplications: (appService.ToList() correctly gets the list of data. This has been well tested.)
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetApplications()
{
var apps = appService.ToList();
if (apps == null)
{
return Json(null, JsonRequestBehavior.AllowGet);
}
return Json(apps, JsonRequestBehavior.AllowGet);
}
In the success function of your ajax call
$.ajax({
....
success: function (data) {
$.each(data, function(index, item) {
var row = $('<tr></tr>'); // create new table row
row.append($('<td></td>').text(item.AppStringID));
row.append($('<td></td>').text(item.ApplicationCategoryID));
row.append($('<td></td>').text(item.Description));
$('#dashboard').append(row); // add to table
});
$('#AppTableID').show();
},
....
});
Notes: You should probably include a tbody element as a child of your table and add the rows to that. Your foreach loop only needs to be #foreach (var item in Model.apps) {.. (the collection has been initialized in the constructor). You also don't need the if (apps == null) {..} condition in the GetApplications method