PrettyFaces - wrong parameters via f:params tag - url-parameters

I can't figure out why the below code in the view:
<ui:repeat value="#{postsController.posts}" var="post">
<tr>
<td>#{post.title}</td>
<td>
<pretty:link mappingId="comments">
<f:param value="#{post.id}"/>
Comments
</pretty:link>
</td>
<td>
<pretty:link mappingId="edit">
<f:param value="#{post.id}"/>
Edit
</pretty:link>
</td>
<td>Delete</td>
</tr>
</ui:repeat>
and this one in the bean:
#Component
#ManagedBean
#RequestScoped
#URLMappings(mappings = {
#URLMapping(id = "posts", pattern = "/posts/", viewId = "/faces/posts/list.xhtml"),
#URLMapping(id = "edit", pattern = "/posts/#{postsController.id}/edit", viewId = "/faces/posts/edit.xhtml"),
#URLMapping(id = "new", pattern = "/posts/new", viewId = "/faces/posts/new.xhtml")
})
public class PostsController {
#Autowired
private PostService postService;
private List<Post> posts;
private Post post = new Post();
private Long id;
public List<Post> getPosts() {
return postService.findAll();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Post getPost() {
if(!post.isNew()) {
this.post = postService.findById(id);
}
System.out.println("++++++++++++++ getPost: " + post);
return post;
}
public void setPost(Post post) {
System.out.println("++++++++++++++setPost: " + post);
this.post = post;
}
public String create(final Post post) {
postService.save(post);
return "pretty:posts";
}
public String update(final Post post) {
System.out.println("++++++++++ update post: " + post);
postService.save(post);
return "pretty:posts";
}
}
The edit page:
<h:form>
<div class="row">
<div class="small-3 columns">
<label for="right-label" class="right inline">Title</label>
</div>
<div class="small-9 columns">
<h:inputText value="#{postsController.post.title}" required="true"/>
<p>
<h:commandButton value="Update" type="submit"
action="#{postsController.update(postsController.post)}"
styleClass="button radius"/>
</p>
</div>
</div>
</h:form>
give the wrong behaviour as follows:
when I edit an existing post, there is no title displayed in the texfield on the edit page, as if there is no ID passed from the parameters. However teh URL is correct: posts/1/edit.
after creating a new Post and hitting the edit link, the title of the Post is displayed correctly.
when I create another new Post, the title textfield id filled with one of the last Post.
update method, even it is called, keeps the original title value and never updates the existing Post.
What am I doing wrong here?
Thannk you.

Related

Asp.Net MVC 3 formcollection losing data after submit

I have a Asp.Net MVC 3 app and after I click on my submit button I want to validate the info passed in the formcollection argument.. and if it's not valid I return a jSon.. but after that my formcollection always returns null
this happens in chrome and FFox.. in IE it works fine
my view:
<li id="opc-register" class="section allow">
<div id="checkout-step-register" class="step a-item" style="display: none;">
<form id="co-register-form" action="">
<div id="checkout-register-load">
#Html.Action("OpcRegisterForm", "Checkout")
</div>
</form>
<script type="text/javascript">
Register.init('#co-register-form', '#(storeLocation)checkout/OpcSaveRegister/');
</script>
<div class="buttons" id="register-buttons-container">
<button type="button" class="paymentmethodnextstepbutton" onclick="Register.save()">
<span>#T("Common.Continue")</span>
</button>
<span class="please-wait" id="register-please-wait" style="display: none;">
<img src="#Url.Content("~/Content/Images/ajax_loader_small.gif")"
alt="#T("Common.LoadingNextStep")" title="#T("Common.LoadingNextStep")" />
#T("Common.LoadingNextStep")</span>
</div>
</div>
</li>
my controller
[HttpPost]
public ActionResult OpcSaveRegister(FormCollection form)
{
var registerModel = PrepareRegisterModel();
registerModel.Email = form["Email"];
registerModel.FirstName = form["FirstName"];
...
if (TryValidateModel(registerModel))
{
....
}
//If we got this far, something failed, redisplay form
return Json(new
{
update_section = new UpdateSectionJsonModel()
{
name = "register",
html = RenderPartialViewToString("OpcRegister", registerModel)
},
goto_section = "register"
});
}
Do not use FormCollection on posts with MVC. Use a strongly typed ViewModel that contains all of the properties that can be submitted in your form on a post.
For example you could have a class like :
public class RegisterViewModel
{
public string FirstName { get; set; }
public string Email { get; set; }
//...
}
And in your view you'd set these properties with:
#Html.EditorFor(m => m.FirstName)
#Html.EditorFor(m => m.Email)
and then for your Action you'd have
[HttpPost]
public ActionResult OpcSaveRegister(RegisterViewModel registerModel)
{
//...
}

Setting value in Javascript results in null property at controller - MVC

I'm fairly new to MVC (and web development in general) and I keep coming across several 'gotchas' which result in unexpected behaviour. I am using Kendo UI, however I'm 99% certain that my problem is due to my lack of understanding of either Javascript or MVC rather than anything to do with Kendo.
You should be able to reproduce the problem using the following code:
Models:
public class DemoClass
{
public int id { get; set; }
public string randomData { get; set; }
public List<DemoPartyDetails> partyDetails { get; set; }
public DemoClass()
{
partyDetails = new List<DemoPartyDetails>();
}
}
public class DemoPartyDetails
{
public int id { get; set; }
public string firstName { get; set; }
public string surname { get; set; }
public string gender { get; set; }
public DemoPartyDetails()
{
}
}
Controller:
public class DemoController : Controller
{
// GET: Demo
public ActionResult Index()
{
DemoClass demo = new DemoClass();
return View(demo);
}
[HttpPost]
public ActionResult Create(DemoClass model)
{
try
{
if (model.partyDetails[0].gender != null)
Console.WriteLine("Party details populated");
else
Console.WriteLine("Something went wrong...");
return RedirectToAction("Index");
}
catch
{
return View();
}
}
}
View:
#model DemoPortal.Models.DemoClass
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
#using (Html.BeginForm("Create", "Demo", FormMethod.Post))
{
<div>
#Html.EditorFor(model => model.randomData)
</div>
<div>
<a class="k-button k-button-icontext k-add-button" href="#"><span class="k-icon k-i-add"></span>Add Party</a>
#(Html.Kendo().ListView(Model.partyDetails)
.Name("demoListView")
.TagName("div")
.ClientTemplateId("demoTemplate")
.DataSource(dataSource => dataSource
.Model(model => model.Id(x => x.id))
)
.Editable(editable => editable.TemplateName("DemoPartyDetails"))
)
</div>
<input type="submit" value="Submit" />
}
</body>
</html>
<script type="text/x-kendo-tmpl" id="demoTemplate">
<div class="demoParty">
<h3>#:firstName#</h3>
<span>#:surname#</span>
<input type="hidden" name="PartyDetails[#:index(data)#].firstName" value="#:firstName#" />
<input type="hidden" name="PartyDetails[#:index(data)#].surname" value="#:surname#" />
<input type="hidden" name="PartyDetails[#:index(data)#].gender" value="#:gender#" />
</div>
</script>
<script>
$(function() {
var listView = $("#demoListView").data("kendoListView");
$(".k-add-button").click(function(e) {
listView.add();
e.preventDefault();
});
});
function index(dataItem) {
var data = $("#demoListView").data("kendoListView").dataSource.data();
return data.indexOf(dataItem);
}
function maleClick(e) {
document.getElementById("gender").value = "M";
document.getElementById("randomData").value = "random";
var maleButton = document.getElementById("IsMale");
var femaleButton = document.getElementById("IsFemale");
femaleButton.classList.remove("k-primary");
maleButton.classList.add("k-primary");
};
function femaleClick(e) {
document.getElementById("gender").value = "F";
document.getElementById("randomData").value = "random";
var maleButton = document.getElementById("IsMale");
var femaleButton = document.getElementById("IsFemale");
maleButton.classList.remove("k-primary");
femaleButton.classList.add("k-primary");
};
</script>
PartyDetails Editor Template
#model DemoPortal.Models.DemoPartyDetails
#using (Html.BeginForm())
{
<div>
<div>
<label>Gender:</label>
#(Html.Kendo().Button()
.Name("IsMale")
.Content("Male")
.HtmlAttributes(new { type = "button" })
.Events(ev => ev.Click("maleClick")))
#(Html.Kendo().Button()
.Name("IsFemale")
.Content("Female")
.HtmlAttributes(new { type = "button", #class = "k-primary" })
.Events(ev => ev.Click("femaleClick")))
</div>
#(Html.HiddenFor(model => model.id))
#(Html.EditorFor(model => model.gender))
#(Html.EditorFor(model => model.firstName))
#(Html.EditorFor(model => model.surname))
<div class="btnArea">
<a class="k-button k-update-button" href="\\#"><span class="k-icon k-update"></span></a>
<a class="k-button k-cancel-button" href="\\#"><span class="k-icon k-cancel"></span></a>
</div>
</div>
}
When running this code, I can click the button to add a new party, the editor template appears as expected and I press the 'Male' button, which populates the gender field with "M".
I then fill in the other two fields with generic "Test" and "Person" data before confirming the entry and then pressing submit.
What I find when I place a breakpoint at the controller however is that the model being passed through has the gender set to null. The first name and surname ("Test" and "Person") are fully populated however. The randomData is also fully populated as expected.
Interestingly, if I go back and manually type something like "Male" into the gender field, that is now also populated. It's only when I try to use javascript to set the value that it's null.
The ultimate goal is to have a hidden field populated by javascript when a button is pressed, so if someone could point out my mistake it would be very much appreciated!
Turns out that you need to trigger the change event of the editor template after changing values through javascript.
$("#gender").trigger("change");

ASP.NET MVC Controller method receiving empty object from jQuery

I have a jQuery script that captures a form into an object and is supposed to send that object to a controller method. Here's the script:
var modalConfirm = function (callback) {
$("#modal-btn-si").on("click", function () {
callback(true);
$("#modal-confirm").modal('hide');
});
$("#modal-btn-no").on("click", function () {
callback(false);
$("#modal-confirm").modal('hide');
});};
function confirmar(form, text) {
$("#modal-confirm").modal('show');
modalConfirm(function (confirm) {
if (confirm) {
enviar(form);
}
}); };
function enviar(form) {
debugger;
var datos = $('#' + form).serializeArray(),
dataObj = {};
$(datos).each(function (i, field) {
dataObj[field.name] = field.value;
});
if (typeof dataObj["precio"] === "undefined") { dataObj["precio"] = 0; }
$.post("NuevaOpcion", {
contentType: "application/JSON",
data: JSON.stringify(dataObj),
}); }
Note: the script was originally much simpler, but trying to fix the issue I'm describing forced me to divide the code in the functions you see.
I created a model to receive the form's data:
public class NuevaOpcionFormModel {
public NuevaOpcionFormModel() { }
public int Id { get; set; }
public string nombre { get; set; }
public int cantidad { get; set; }
public int precio { get; set; }
public int idrespuesta { get; set; }
public int OptionSelectedItem { get; set; }
}
And the controller's method signature:
[HttpPost]
public ActionResult NuevaOpcion (Dayvo.Presupuestador.Web.Models.Form.NuevaOpcionFormModel nuevaOpcion) { ... }
What I've tried
On the script:
.serialize() instead of .serializeArray().
Not serialize at all.
Passing entire 'form' into object and then to controller.
JSON.stringify (actual state) and not using it.
Stablishing each field in data manually.
Stablishing each field in data manually and apllying JSON.stringify.
On the controller:
[FromForm] & [FromBody]
[Bind]
A single variable for each field, matching names and types.
Everything I've tried ends up with the controller's method receiving nothing. I tracked the script (that's why you're seeing a debugger; breakpoint in it), it gets the object into the array correctly, each field with it's proper value:
But still hits the controller with empty object:
Any clue about what I'm doing wrong is more than welcome. Thanks in advance.
EDIT
As requested, here's the view part I'm capturing into the form:
<div class="panel-footer">
#using (Html.BeginForm("NuevaOpcion", "Home", FormMethod.Post, new { #id = "frm_nueva_opcion" })) {
#Html.HiddenFor(m => m.Id)
<div class="row">
<div class="col-md-6">
<div class="form-group" style="margin-bottom: .7em;margin-top: .7em;">
<button class="btn btn-success btn-xs" type="button" onclick=" $('#row-nueva-opcion').toggle()" id="add-opcion">
<span class="glyphicon glyphicon-plus-sign"></span> Añadir nueva opción
</button>
</div>
</div>
</div>
<div class="row" id="row-nueva-opcion" style="display:none">
<div class="col-md-10">
<label>
<input type="checkbox" id="opcion-extra" onclick=" $('#nuevo-precio').attr('disabled', !this.checked);" />
Es opción extra
</label>
<div class="input-group" style="margin-bottom:1.7em;">
<input type="text" placeholder="Opción" class="form-control" name="nombre" style="max-width:70%;">
<input type="number" placeholder="Cantidad" min="1" value="1" class="form-control" name="cantidad" style="max-width:15%;">
<input type="number" placeholder="Precio" class="form-control" id="nuevo-precio" name="precio" style="max-width:15%;" disabled>
<input type="hidden" name="idrespuesta" id="idrespuesta" value="#listItems.Select(x=>x.Value).FirstOrDefault()" />
<div class="input-group-addon">€</div>
<span class="input-group-btn">
<a class="btn btn-primary" data-title="Confirmación de acción" data-toggle="modal" data-target="#modal_confirm" onclick="confirmar('frm_nueva_opcion')">
<span class="glyphicon glyphicon-floppy-disk"></span> Guardar
</a>
</span>
</div>
</div>
<div class="col-md-8">
<div class="form-group">
<label>
¿Para que pregunta es la opción?
#Html.DropDownList("OptionSelectedItem", listItems, new { #class = "form-control" })
</label>
</div>
</div>
</div>
}
</div>
The jquery $.post() method sends data using the default contentType='application/x-www-form-urlencoded; charset=UTF-8' where the data needs to be PlainObject.
For the DefaultModelBinder to bind to your model, the name/value pairs of the object need to match the model properties, so the format needs to be
var data = { Id: someValue, nombre: anotherValue, .... };
To generate that object, either generate it manually, or better, use the .serialize() method (not .serializeArray()) to correctly serialize all form controls. Change the script to
function enviar(form) {
var data = $('#' + form).serialize();
$.post("NuevaOpcion", data, function(response) {
... // code to execute when the response is returned
});
Note it is not clear what you where expecting with the if (typeof dataObj["precio"] === "undefined") { dataObj["precio"] = 0; } code, but it is unnecessary and can be omitted - your precio property is int and it will have a value of 0 if it is not included in the request.
I also strongly recommend you use the HtmlHelper methods to strongly bind to your model, and to ensure the correct name, value and data-val-* attributes are added for 2-way model binding and client side validation.

POST call to Controller’s Method to save textbox data in MVC

Good day! I am curretly working on a project wherein a user fills-up a form and a modal confirmation will pop-up. After verifying the details inside, the user will then click submit to save the data. I tried using this tutorial about POST to controller to save my data in the database. Unfortunately, nothing happens after clicking the Submit button.
Model
public partial class Transaction
{
public int id { get; set; }
public string queue_no { get; set; }
public string name { get; set; }
public string address { get; set; }
public DateTime date { get; set; }
}
Controller
[HttpPost]
public ActionResult Transactions(string Name, string Address,string QueueNo)
{
Transaction trans = new Transaction();
trans.name = Name;
trans.address = Address;
db.Transactions.Add(trans);
db.SaveChanges();
return RedirectToAction("Index");
}
View
<div class="modal-body">
Are you sure you want to submit the following details?
<br/>
<br />
<table class="table">
<tr>
<th>Queue Number</th>
<td id="queuenoo"></td>
</tr>
<tr>
<th>Fullname</th>
<td id="namee"></td>
</tr>
<tr>
<th>Address</th>
<td id="addresss"></td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
Submit
</div>
</div>
Javascript
$('#submit').click(function() {
var url = "/Series/Transactions";
var name = $("#namee").val();
var address = $("#addresss").val();
var queueno = $("#queuenoo").val();
$.post(url, { Name: name, Address: address, QueueNo: queueno });
});
Thanks in advance!
<td> elements do not have a value attribute. You need to use .text() (or .html())
$('#submit').click(function() {
var url = "/Series/Transactions";
var name = $("#namee").text();
var address = $("#addresss").text();
var queueno = $("#queuenoo").text();
$.post(url, { Name: name, Address: address, QueueNo: queueno });
});

Index error in my code controller?

When I run my project index, it shows this error. I have googled it but I have not found a proper solution for this error. So, please someone help me.
The Error message:
"The parameters dictionary contains a null entry for parameter
'chapterIdS' of non-nullable type 'System.Int32' for method
'System.Web.Mvc.ActionResult Index(Int32)' in
'opr.Controllers.QuizeController'. An optional parameter must be a
reference type, a nullable type, or be declared as an optional
parameter.
Parameter name: parameters"
This is my Index code:
#model List<opr.Data.Chapter>
#{
ViewBag.Title = "Index";
}
<h4>Select Chapter</h4>
<div class="container">
<div class="alert-info form-control m-auto w-75 custom-form col-6">
#using (Html.BeginForm("Index", "Quize", FormMethod.Get))
{
<h4>Quizes</h4>
<hr />
foreach (var std in Model)
{
<div class="row">
<div class="col-4"></div>
<div class="col-4">
#Html.RadioButton("searchBy",#std.Chapter_Name, true)
<text>#std.Chapter_Name</text>
</div>
<div class="col-4"></div>
</div>
<hr />
<h3>Questions</h3>
<hr />
<table>
<tbody>
#foreach (var quesion in std.C_QuestionTable)
{
<tr>
<td>
<h5>#quesion.QuestionText</h5>
</td>
</tr>
foreach (var answer in quesion.C_AnswerTable)
{
<tr>
<td>#answer.Options</td>
</tr>
}
}
</tbody>
</table>
}
<input type="submit" value="Create Question" />
}
</div>
</div>
this my controller
public class QuizeController : Controller
{
examsEntities db = new examsEntities();
public ActionResult Index(int chapterIdS)
{
List<C_QuestionTable> ques = new List<C_QuestionTable>();
ViewBag.ques = db.C_QuestionTable.Where(w => w.Id == chapterIdS).ToList();
List<Chapter> model = new List<Chapter>();
model = db.Chapters.Where(w=>w.Id==chapterIdS).ToList();
return View(model);
}
}
Default route expects optional parameter named id:
public ActionResult Index(int id)
{
...
}
Therefore, if your url looks like .../Quize/Index/1 you need to call this parameter id, or register your own route for this controller.
Try with this...
public ActionResult Index(int? chapterIdS)
{
List<C_QuestionTable> ques = new List<C_QuestionTable>();
ViewBag.ques = db.C_QuestionTable.Where(w => w.Id == chapterIdS).ToList();
List<Chapter> model = new List<Chapter>();
model = db.Chapters.Where(w=>w.Id==chapterIdS).ToList();
return View(model);
}
Now parameter will accept the null value.

Resources