I have a simple mvc project consisting of one table named Persons and that table has some attributes like name, age, surname and so on.
I Recently added an attribute to table which is type of bit in SQL and bool in C# and for me it represents some status. If it is ok I put that status to true or false.
In one controller I create an index view of my Persons in the database and I display the status as a checkbox. That is working ok. What I want to do is to change the status if I click on that checkbox instead of using an edit view for all of the atributes.
I just want to save checkbox value from my index view to database.
Some people advised me to create an action in my controller like so:
public ActionResult Save(int id, bool status){}
Where id is id of my person in db and status is a value of the checkbox I clicked.
So how do I call that function with jquery, ajax or javascript and send those params?
I am not so good with ajax and a little bit afraid of it :)
And one more thing I manage to show checkbox value corectly from my databse only in this way:
#Html.CheckBox("somename", item.Status)
<input name="somename" type="hidden" value="false"/>
Any help or advice or sending me to good direction is good!
You have several options. One way would be to place the checkboxes in a (normal) form and then use the jQuery Form plugin to Ajaxify the form:
#using(Html.BeginForm()) {
#Html.Checkbox(...)
}
<script type="text/javascript">
$(document).ready(function () {
$('form').ajaxForm({
success: Saved,
error: HandleError
});
});
function Error(response, status, err) {
// code to handle error here
}
function Saved(responseText, statusText, xhr, $form) {
// code to handle succes, if any
}
</script>
You could, of course, use an #Ajax.BeginForm as well, but this has the advantage of being easily downgradable. Just remove the jQuery form initialisation and you got yourself a regular form : )
Another possibility is to simply use an #Ajax.ActionLink. I wrote a blog post on how to deal with Ajax.ActionLink that I think will help you out.
The signature for your controller action on your question looks correct:
public ActionResult Save(int id, bool status){}
Another options is actually to create a Settings view model (call it what you will), and in there just have a bunch of bool properties to represent the checkboxes:
public class Settings
{
public bool Status { get; set; }
// more properties here
}
then you can bind your action to the Settings object:
public ActionResult Save(int id, Settings settings){}
This will come in handy in case you end up having multiple checkboxes to bind.
Related
All,
I am very new to MVC3 / jQuery combo and have been reading tutorials. While I kind of get the concept, razor syntax etc. I'm still a bit confused on how to implement a basic concept that I'm trying to.
I have a textarea and when someone enters some text into it and hits enter, I want to trigger a ajax call to the server with the content of the text area, and get back a fully formed HTML blurb that I can put in a div. Now as I understand in MVC3 this would be a view, so in a sense I'm rendering a view on the server and sending it back so I can put it in HTML.
Is this possible? Any examples that I can look up to see how this done? I know how to capture keystrokes, get the value etc., it's this partial rendering of a fully formed HTML via ajax that I'm struggling to understand.
Thanks,
You can do with jQuery. This is how it works. you listen for the keydown event of the text area and when there is a keydown, check what key it is.if it is enter key, then make a jQuery ajax post call to a server page (action method in your controller with the data).Save the data there to your tables and return the markup of what you want and return that. in your script load it to your relevant div.
HTML
//Load jQuery library in your page
<textarea id="txtComment" > </textarea>
<div id="divComment"></div>
Javascript
$(function(){
$("#txtComment").keydown(function (event) {
if (event.keyCode == 10 || event.keyCode == 13) {
var comment=$("#txtComment").val();
comment=encodeURIComponent(comment);
$.post("yourcontroller/actionmethod?data="+comment,function(response){
$("#divComment").html(response);
});
}
});
});
and your controller action method
public ActionResult actionmethod(string data)
{
//Do some sanitization on the data before saving.
// Call your method to save the data to your tables.
CommentViewModel objCommentVM=new CommentViewModel();
objCommentVM.Comment=data;
return View("PartialCommentView",objCommentVM);
}
You should have a ViewMolde class called "CommentViewModel" like this
public class CommentViewModel
{
public string Comment{ set; get; }
}
and you should have a View called PartialCommentView which is strongly typed to CommentViewModel
#model FlashRack.ViewModel.RackViewModel
#{
Layout = null;
}
<div>
#Model.Comment
</div>
If you are simply returning a string, instead of returning a View, you can simply return the string using Return Content("your string here") method as well. But i prefer returning the ViewModel via View because it is more scalable and clean approach to me.
Your action method will return the markup you have in your PartialCommentView with the data.
Keep in mind that you have to take care of the special characters and escaping them properly.
I'm in some trouble here. I have a view in which a company can thumbs up or down users of our site. The users are listed in a table and a column has the little hand images for the company to vote for or against the user. I had programmed an ActionLink there, however, I don't want a postback to happen every time a company vote on a user.
I decided to fill a list with the user IDs the company votes on and then, when leaving the page, a filter would intercept the request, get the list and process the votes. In this post I was taught how to initialize Filter parameters when calling the Action, but as you can see, I need a way for the Filter to get the Lists when the user exits the View, not in an Action.
I wouldn't want to use code-behind because, paired with MVC, it is not a best practice, but postbacks are not an option either.
Here's what I have so far:
public ActionResult ListUsers()
{
// Create a List with user models and send it to a View,
// which generates a WebGrid
return View(userList);
}
public class PromoteUsersFilter : ActionFilterAttribute
{
public int[] UsersToPromote { get; set; }
public int[] UsersToScrewWith { get; set; }
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
//insert promoting logic here
}
}
I believe there is a simple way of doing it, since most websites have this funcionality. Can anyone guide me with this?
Why not use AJAX that calls into your controller methods? If you set up your json properly, it will still be deserialized into an object, too.
This is OK even in the MVC mindset as far as I know. If you need to persist your data, but not update the entire page it is the only way that I know. You can even swap out entire partial views using AJAX.
I think the common misconception here is that the View portion (of MVC) is not just one page, but actually made up of a number of views smashed into the one page. So, updating one of those views separately does not really break the pattern.
Definitely go for the AJAX solution:
It could look like this in your view:
<div>
<span class="cssUpvote" id="upvote"><span>
<span class="cssDownvote" id="downvote"></span>
</div>
with some Jquery
<script>
$(document).on('click', 'upvote', function (event) {
$.ajax({
type: 'POST',
url: '/Votes/Upvote',
data: { id: companyId }
});
});
$(document).on('click', 'downvote', function (event) {
$.ajax({
type: 'POST',
url: '/Votes/Downvote',
data: { id: companyId }
});
});
</script>
And then your actions on the Controller
[HttpPost]
public ActionResult Upvote(int id)
{
//Do something with the (company)id
return Json();
}
[HttpPost]
public ActionResult Downvote(int id)
{
//Do something with the (company)id
return Json();
}
I am using the Wizard control described in http://afana.me/post/create-wizard-in-aspnet-mvc-3.aspx
It works great, but I need to have Multiple HttpPost within the same Controller. In my scenario, I need to add to a collection before moving to next step. In the partial view for that step. I have following set up:
#using (Html.BeginForm("AddJobExperience", "Candidate"))
{
<input type="submit" value="Add Experience" />
}
When I press the Add Experience input, it is routed to the
[HttpPost, ActionName("Index")]
public ActionResult Index(CandidateViewModel viewModel)
{
}
instead of
[HttpPost, ActionName("AddJobExperience")]
public ActionResult AddJobExperience(CandidateViewModel col)
{
}
what am I doing wrong?
It sounds like you need to break up your CandidateViewModel into separate ViewModels and your big Wizard View into separate Views so that there is one per action for each step of the wizard.
Step one they add the job experience, so have a view, viewmodel and an action for that, Step two they do whatever else and you have a separate view, viewmodel and action for that as well. etc, etc
Breaking up your CandidateViewModel into separate ViewModels will mean that you can just focus on the data required for that step, and can add the validation, then when they click submit, it posts the data to the next step.
Then, when you want to improve the UI behaviour, add some AJAX, and maybe use something like JQuery UI Tabs to make it behave more like a wizard in a desktop app.
It sounds like you still have nested forms. Don't do this, it is not valid HTML.
You have 2 options here, depending on what you are trying to achieve. If you want to post your job experiences separately one at a time, then put them in their own #using(Html.BeginForms, but don't nest them in an outer form. When a user clicks the Add Experience button, do your work on that one experience and then return a new view to the user.
If you want to post all of the job experiences at the same time, then wrap all of them in a single #using(Html.BeginForm and do not put #using(Html.BeginForm in your partial views. See another question I answered here for more info on how to post a collection of items in a single HTTP POST.
The 2nd method is what it sounds like you are trying to achieve, and for this, you should probably use AJAX to add multiple job experiences to your collection without doing a full postback. You can then do 1 HTTP POST to submit all job experiences in the collection to your wizard controller. It's not very difficult to implement a feature like this:
Given I can see the Add Experience button
When I click the Add Experience button
Then I should see a new experience partial view with input fields
And I should enter data in these fields
When I click the Add Experience button a second time
Then I should see another new experience partial view with input fields
And I should enter data in these fields
When I click the Add Experience button a third time
Then I should see a third new experience partial view with input fields
And I should enter data in these fields
When I click the Next button in the wizard
Then my controller will receive data for all 3 experiences I submitted in a single form
you need to use ActionMethodSelectorAttribute or ActionNameSelectorAttribute which allow to add new attribute on action to call different action on respective of button click
In View:
#using (Html.BeginForm())
{
<input type="submit" value="Add Experience" name="AddExperience" />
<input type="submit" value="Add Experience" name="AddJobExperience" />
}
add new class FormValueRequiredAttribute in application which extend ActionMethodSelectorAttribute class to check on which button is clicked
//controller/FormValueRequiredAttribute.cs
public class FormValueRequiredAttribute : ActionMethodSelectorAttribute
{
public string ButtonName { get; set; }
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
var req = controllerContext.RequestContext.HttpContext.Request;
return !string.IsNullOrEmpty(req.Form[this.ButtonName]);
}
}
then you should add this attribute on action to call corresponding action
In Controller
[HttpPost]
[FormValueRequired(ButtonName = "AddExperience")]
public ActionResult Index(CandidateViewModel viewModel)
{
return View();
}
[HttpPost]
[ActionName("Index")]
[FormValueRequired(ButtonName = "AddJobExperience")]
public ActionResult AddJobExperience_Index(CandidateViewModel viewModel)
{
return View();
}
Note if your Html.BeginForm method in Index.cshtml then you don't need specify ActionName attribute on Index Action, now AddJobExperience_Index act same as Index Action.
I want to pass two values from view to controller . i.e., #Model.idText and value from textbox. here is my code:
#using HTML.BeginForm("SaveData","Profile",FormMethod.Post)
{
#Model.idText
<input type="text" name="textValue"/>
<input type="submit" name="btnSubmit"/>
}
But problem is if i use "Url.ActionLink() i can get #Model.idText . By post action i can get textbox value using FormCollection . But i need to get both of this value either post or ActionLink
using ajax you can achieve this :
don't use form & declare your attributes like this in tags:
#Model.idText
<input type="text" id="textValue"/>
<input type="submit" id="btnSubmit"/>
jquery:
$(function (e) {
// Insert
$("#btnSubmit").click(function () {
$.ajax({
url: "some url path",
type: 'POST',
data: { textField: $('#textValue').val(), idField: '#Model.idText' },
success: function (result) {
//some code if success
},
error: function () {
//some code if failed
}
});
return false;
});
});
Hope this will be helpful.
#using HTML.BeginForm("SaveData","Profile",FormMethod.Post)
{
#Html.Hidden("idText", Model.idText)
#Html.TextBox("textValue")
<input type="submit" value="Submit"/>
}
In your controller
public ActionResult SaveData(String idText, String textValue)
{
return null;
}
I'm not sure which part you are struggling with - submitting multiple values to your controller, or getting model binding to work so that values that you have submitted appear as parameters to your action. If you give more details on what you want to achieve I'll amend my answer accordingly.
You could use a hidden field in your form - e.g.
#Html.Hidden("idText", Model.idText)
Create a rule in global.asax and than compile your your with params using
#Html.ActionLink("My text", Action, Controller, new { id = Model.IdText, text =Model.TextValue})
Be sure to encode the textvalue, because it may contains invalid chars
Essentially, you want to engage the ModelBinder to do this for you. To do that, you need to write your action in your controller with parameters that match the data you want to pass to it. So, to start with, Iridio's suggestion is correct, although not the full story. Your view should look like:
#using HTML.BeginForm("SaveData","Profile",FormMethod.Post)
{
#Html.ActionLink("My text", MyOtherAction, MaybeMyOtherController, new { id = Model.IdText}) // along the lines of dommer's suggestion...
<input type="text" name="textValue"/>
<input type="submit" name="btnSubmit"/>
#Html.Hidden("idText", Model.idText)
}
Note that I have added the #Html.Hidden helper to add a hidden input field for that value into your field. That way, the model binder will be able to find this datum. Note that the Html.Hidden helper is placed WITHIN your form, so that this data will posted to the server when the submit button is clicked.
Also note that I have added dommer's suggestion for the action link and replaced your code. From your question it is hard to see if this is how you are thinking of passing the data to the controller, or if this is simply another bit of functionality in your code. You could do this either way: have a form, or just have the actionlink. What doesn't make sense is to do it both ways, unless the action link is intended to go somewhere else...??! Always good to help us help you by being explicit in your question and samples. Where I think dommer's answer is wrong is that you haven't stated that TextValue is passed to the view as part of the Model. It would seem that what you want is that TextValue is entered by the user into the view, as opposed to being passed in with the model. Unlike idText that IS passed in with the Model.
Anyway, now, you need to set up the other end, ie, give your action the necessary
[HttpPost]
public ActionResult SaveData(int idText, string textValue) // assuming idText is an int
{
// whatever you have to do, whatever you have to return...
}
#dommer doesn't seem to have read your code. However, his suggestion for using the Html.ActionLink helper to create the link in your code is a good one. You should use that, not the code you have.
Recapping:
As you are using a form, you are going to use that form to POST the user's input to the server. To get the idText value that is passed into the View with the Model, you need to use the Html.Hidden htmlhelper. This must go within the form, so that it is also POSTed to the server.
To wire the form post to your action method, you need to give your action parameters that the ModelBinder can match to the values POSTed by the form. You do this by using the datatype of each parameter and a matching name.
You could also have a complex type, eg, public class MyTextClass, that has two public properties:
public class MyTextClass
{
public int idText{get;set}
public string TextValue{get;set;}
}
And then in your controller action you could have:
public ActionResult SaveData(MyTextClass myText)
{
// do whatever
}
The model binder will now be able to match up the posted values to the public properties of myText and all will be well in Denmark.
HTH.
PS: You also need to read a decent book on MVC. It seems you are flying a bit blind.
Another nit pick would be to question the name of your action, SaveData. That sounds more like a repository method. When naming your actions, think like a user: she has simply filled in a form, she has no concept of saving data. So the action should be Create, or Edit, or InformationRequest, or something more illustrative. Save Data says NOTHING about what data is being saved. it could be credit card details, or the users name and telephone...
I am still new to MVC, so sorry if this is an obvious question:
I have a page where the user can choose one of several items. When they select one, they are taken to another form to fill in their details.
What is the best way to transfer that value to the form page?
I don't want the ID of the item in the second (form) pages URL.
so it's /choose-your-item/ to /redemption/ where the user sees what was selected, and fills the form in. The item selected is displayed, and shown in a hidden form.
I guess one option is to store in a session before the redirect, but was wondering if there was another option.
I am using MVC3
Darin Dimitrov's answer would be best if you don't need to do any additional processing before displaying the /redemption/ page. If you do need to some additional processing, you're going to have to use the TempDataDictionary to pass data between actions. Values stored in the TempDataDictionary lasts for one request which allows for data to be passed between actions, as opposed to the values stored in the ViewDataDictionary which only can be passed from an action to a view. Here's an example below:
public ActionResult ChooseYourItem()
{
return View();
}
[HttpPost]
public ActionResult ChooseYourItem(string chosenItem)
{
TempData["ChosenItem"] = chosenItem;
// Do some other stuff if you need to
return RedirectToAction("Redemption");
}
public ActionResult Redemption()
{
var chosenItem = TempData["ChosenItem"];
return View(chosenItem);
}
If you don't want the selected value in the url you could use form POST. So instead of redirecting to the new page, you could POST to it:
#using (Html.BeginForm("SomeAction", "SomeController"))
{
#Html.DropDownListFor(...)
<input type="submit" value="Go to details form" />
}
To help others, this is how I resolved my issue of needing multiple buttons posting back, and wanting to pass a different Id each time.
I have a single form on the page, that posts back to my controller:
The Form:
#using (Html.BeginForm("ChooseYourItem", "Item", FormMethod.Post))
{
And the code
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ChooseYourItem(string itemId)
{
TempData["ITEMID"] = itemId
return RedirectToAction("Create", "Redemption");
}
Then, inside the form, I create buttons whose name == "itemId", but has a different value each time.
For example
<strong>Item 1</strong>
<button value="123" name="itemid" id="btn1">Select</button>
<strong>Item 2</strong>
<button value="456" name="itemid" id="btn2">Select</button>