How to change style of DIV element in view from controller? - c#

I have the following div in my view:
<div id="review">
REVIEW:
<p>
<%:ViewData["Review"]%>
</p>
<input name="submit" id="submit" type="submit" value="OK"/>
</div>
How can I set DIV visibility to visible inside of controller when a certain button is clicked?
This is a code fragment in my controller:
public ActionResult Index(EsafeModel model,string submit, string create)
{
if (button.Equals("Create"))
{
ViewData["Review"] = ESafeData.CreateReview(eSafe);
}
else if (button.Equals("OK"))
{
if (ESafeData.Create(eSafe))
{
ViewData["Message"] = "E-Safe data created!!!";
}
}
}

You can't do this directly as div is on client side and the controller is server side.
What you can do is have a property in your model which is bound to view .This can have the value of visibility attribute for div and then you can assign it using server tags to div
Below is a sample code snippet
<div id="elementid" style="visibility:'<%=Model.Visible %>'"/>
On the click of button you can return the same view and model but this time model will have Visible ="hidden"

Related

asp.net razor pages: binding checkbox result to dataset

I am completely new to a project I am to maintain.
Simply question: I have in my cshtml page (which I understand are razor pages?) set up a few checkboxes and a label to test the bound class behind it.
This I got to work:
#model Application.Areas.Cms.Models.ProduktBeispielViewModel
<label>#Model.Test</label>
And the VM:
public string Test { get; set; } = "THIS IS A TEST";
And happy me: the words are displayed on my page. So the binding is working.
Now I put up a few checkboxes and once a submit button is pressed, I need to retrieve each checkbox and see if their value is checked or unchecked (shouldnt be too hard).
I first now just tried to display a value (eg true or false) from my VW onto my existing checkboxes.
This is what I did:
public bool Test2 { get; set; } = true;
CSHTML:
<input type="checkbox" name="FoodTrends" value="#Model.Test2" />
I am seeing my checkbox, but it is unchecked.
1.) Why is my simple binding not working? is "value" not the right property?
2.) How would I retrieve my value from this checkbox
Thank you all!
Please have a look at this:
I am returning my model, with the value on Test2 being false
Now this is my exact code in my view:
<input type="checkbox" name="FoodTrends" value="#Model.Test2" checked="#Model.Test2" />
And the result is that the checkbox is checked, even though the value is set to false.
I have noticed also that my checkboxes are inside "<form>" tag.
EDIT:
Razorcode (briefly):
#model Application.Areas.Cms.Models.ProduktBeispielViewModel
#{
ViewBag.PopupHeadline = "Produktbeispiele";
ViewBag.PopupSubHeadline = Model.Item != null ? Model.Item.NameInCurrentLang : "";
ViewBag.HideLanguageComparison = true;
}
#section TabMenu
{
<ul>
<li>Einstellungen</li>
<li>Bild</li>
</ul>
}
<form action="#Url.Action("SaveIndex")" method="POST" id="idForm">
#Html.HiddenFor(m => m.AutoCloseWindow)
#Html.HiddenFor(m => m.Item.Id)
<input type="checkbox" name="FoodTrends" value="#Model.Test2" />
</form>
The checkbox wouldn't work that way you have to use the checked attribute to get selected your checkbox.
#model Practice_web.Models.TestModel
#{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about building Web apps with ASP.NET Core.</p>
</div>
<div>
<input type="checkbox" name="FoodTrends" value="#Model.Test2" checked="#Model.Test2" />
</div>
Action Controller
public IActionResult Index()
{
var model = new TestModel { Test2 = true };
return View(model);
}
Here is the demo video link
Demo Link
Please try this. This works for me like a charm
I don't know if this is a bug or I just don't understand how razor pages work but I have to new up the model first in the AddModel method then it seems to pick up the default value I set in the POCO for my checkbox bool property.
[BindProperty]
public NewMember? User { get; set; }
public AddModel()
{
User = new NewMember();
}

List hidden value passes wrong value to controller

I have a list In my view. For each row, I view button and I am passing Id value as hidden. But when I click any button it is passing wrong hidden value to the controller. Always it passes the first-row hidden value to the controller.
View:
#foreach (var list in Model)
{
<div>
<div > #( ((int)1) + #Model.IndexOf(list)).</div>
<div >#list.details</div>
<div class="col-md-2 row-index">
<button class="btn btn-link" type="submit" name="action:view" id="view">View</button>
<input type="hidden" name="viewId" id="viewId" value="list.WId" />
</div>
</div>
}
Controller:
[HttpPost]
[MultipleButton(Name = "action", Argument = "view")]
public ActionResult ViewDetail(string viewId)
{
return RedirectToAction("ViewDetails");
}
To get all values you need to change the input value type in your controller to array of strings.
I hope that this solution can help you
[HttpPost]
[MultipleButton(Name = "action", Argument = "view")]
public ActionResult ViewDetail(string[] viewId)
{
return RedirectToAction("ViewDetails");
}
if you want to get the exact value you need to duplicate the form within your foreach
in this case you should write somthing like this :
#foreach (var list in Model)
{
<div>
<div > #( ((int)1) + #Model.IndexOf(list)).</div>
<div >#list.details</div>
<div class="col-md-2 row-index">
<form ... > // complete your form attributes
<button class="btn btn-link" type="submit" name="action:view" id="view">View</button>
<input type="hidden" name="viewId" id="viewId" value="list.WId" />
</form>
</div>
</div>
}
Note : You should delete the global form
You should have one form for each row. then you submit that row.
Otherwise as you state it passes first value.
You are setting each value to the same element ID (which is invalid anyway) and name. When you submit your form (which would be more helpful to fully answer your question) it is finding the first element that matches that criteria and submitting it.
There are multiple ways to resolve this such as the already mentioned form per entry but the other preference would be to modify you button to a div and add a click handler to pass the specific value to a js function which would then submit to the controller. Its a preference choice regarding how tightly coupled you want your front end. But the main problem is your element naming convention.

asp.net core mvc model binding with jquery repeater

I am using jquery repeater in my form to dynamically add only a part of input group to form. I did try but couldn't get inputs bind to model, I went blind.
Here my model.
public class SuggestionCreateEditViewModel
{
public Guid[] DetectionId { get; set; }
public SuggestionCreateEditRepeatedModel[] Repeated { get; set; }
}
public class SuggestionCreateEditRepeatedModel
{
public Guid To { get; set; }
public string Description { get; set; }
public DateTime Deadline { get; set; }
}
Form, I removed a lot of parts of form for brevity
<div class="col-lg-9 col-md-9 col-sm-12">
<select asp-for="DetectionId" asp-items="ViewBag.AllDetections" class="m-bootstrap-select m_selectpicker toValidate"
multiple data-actions-box="true" data-width="100%"></select>
</div>
<div class="col-lg-9 col-md-9 col-sm-12 input-group date">
<input name = "Repeated.Deadline" type="text" readonly class="form-control toValidate dtDueDate" />
</div>
<div class="col-lg-12 col-md-12 col-sm-12">
<textarea name = "Repeated.Description" class="form-control toValidate txtSuggestion" type="text" >
</textarea>
</div>
after adding a new repeated section to form and before posting it to server, if I form.serailizeArray() it returns collection like as follows (what jquery form repeater dynamically shape names I believe)
{name: "DetectionId", value: "afca1b82-0455-432e-c780-08d6ac38b012"}
{name: "[0][Repeated.To][]", value: "b1176b82-1c25-4d13-9283-df2b16735266"}
{name: "[0][Repeated.Deadline]", value: "04/04/2019"}
{name: "[0][Repeated.Description]", value: "<p>test 1</p>"}
{name: "[1][Repeated.To]", value: "188806d8-202a-4787-98a6-8dc060624d93"}
{name: "[1][Repeated.Deadline]", value: "05/04/2019"}
{name: "[1][Repeated.Description]", value: "<p>test 2</p>"}
and my controller
[HttpPost]
public IActionResult CreateSuggestion(SuggestionCreateEditViewModel model, IFormFile[] documents)
{...
controller couldn't get Repeated binded, only DetectionId is binded. How should I shape my model to get the data?
Here is a working demo for with jquery.repeater.js, pay attention to this line <div data-repeater-list="Repeated"> which will format the field like name="Repeated[0][Description]"
#model TestCore.Models.SuggestionCreateEditViewModel
#{
ViewData["Title"] = "Contact";
}
<form class="repeater" asp-action="CreateSuggestion" method="post">
<!--
The value given to the data-repeater-list attribute will be used as the
base of rewritten name attributes. In this example, the first
data-repeater-item's name attribute would become group-a[0][text-input],
and the second data-repeater-item would become group-a[1][text-input]
-->
<div data-repeater-list="Repeated">
<div data-repeater-item>
<div class="col-lg-9 col-md-9 col-sm-12">
<select asp-for="DetectionId" asp-items="ViewBag.AllDetections" class="m-bootstrap-select m_selectpicker toValidate"
multiple data-actions-box="true" data-width="100%"></select>
</div>
<div class="col-lg-12 col-md-12 col-sm-12">
<textarea name="Description" class="form-control toValidate txtSuggestion" type="text">
</textarea>
</div>
</div>
</div>
<input data-repeater-create type="button" value="Add" />
<input type="submit" value="Submit"/>
</form>
#section Scripts{
<!-- Import repeater js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.repeater/1.2.1/jquery.repeater.js"></script>
<script>
$(document).ready(function () {
$('.repeater').repeater({
// (Optional)
// start with an empty list of repeaters. Set your first (and only)
// "data-repeater-item" with style="display:none;" and pass the
// following configuration flag
initEmpty: true,
// (Optional)
// "show" is called just after an item is added. The item is hidden
// at this point. If a show callback is not given the item will
// have $(this).show() called on it.
show: function () {
$(this).slideDown();
},
// (Optional)
// "hide" is called when a user clicks on a data-repeater-delete
// element. The item is still visible. "hide" is passed a function
// as its first argument which will properly remove the item.
// "hide" allows for a confirmation step, to send a delete request
// to the server, etc. If a hide callback is not given the item
// will be deleted.
hide: function (deleteElement) {
if (confirm('Are you sure you want to delete this element?')) {
$(this).slideUp(deleteElement);
}
},
// (Optional)
// Removes the delete button from the first list item,
// defaults to false.
isFirstItemUndeletable: true
})
});
</script>
}
By the looks of things, the controller cannot bind the repeater properties back to your view model because the naming of the posted content does not match the naming in your view model (as Topher mentioned).
The DetectionId is named correctly though because the name of the property matches and its not an array.
To resolve an array we need to make sure we include the property name in the form as well as an index so that mvc model binding knows where to bind the result to.
With that, can you try changing the format of the name to:
Repeated[0].To
That should match up with your controller and correctly bind.
For more info on binding, please see this.

Pass Selected Dropdown Value to Controller using a Button

In the example below when clicking the button the value selected in the dropdownlist should be passed to the controller, but its not. How can I pass the value?
View:
#model BillingModel
...
<select id="ddl" asp-for="SelectedCompanyID" asp-items="Model.Companies" class="form-control"></select>
<a asp-action="Create" asp-controller="Invoice" asp-route-id="#Model.SelectedCompanyID" class="btn btn-primary btn-sm"></span> Create Invoice</a>
....
Model:
public class BillingModel
{
public int SelectedCompanyID { get; set; }
public SelectList Companies { get; set; }
}
Your link is using razor code to specify the route id value which is server side code. It does not change on the client side just because a option is selected.
Either use a form that makes a GET and submits the option value
<form asp-controller="Invoice" asp-action="Create" method="get">
<select id="ddl" asp-for="SelectedCompanyID" asp-items="Model.Companies" class="form-control"></select>
<input type="submit" value="Create Invoice" /> // you can style this to look like your link if you want
</form>
Note that this will generate the url with a query string value for the id, not a route value (i.e. it will generate ../Invoice/Create?id=1, not ../Invoice/Create/1)
Alternatively, you could use javascript/jquery to make the redirect by building a url based on the selected option
<a id="create" href="#" class="btn btn-primary btn-sm">Create Invoice</a>
$('#create').click(function() {
var baseUrl = '#Url.Action("Create", "Invoice")';
location.href = baseUrl + '/' + $('#SelectedCompanyID').val();
}

Redirecting parent page from Html.renderAction child without using Ajax, Java, Jquery or such

I have a problem where I have a form in a Html.RenderAction and after submitting the form I have to reload the parent but I keep getting "Child actions can not perform redirect actions". So how can I solve it without Ajax etc.
In my parent I have:
#{
var UserReviewExist = Model.Reviews.FirstOrDefault(x => x.AspNetUser.UserName == Name.AspNetUser.UserName);
}
#{if (UserReviewExist == null)
{
Html.RenderAction("ReviewCreate", "Reviews", new { BookID = Model.Id });
}
}
My RenderAction View contains this:
#model Trigger_Happy_Bunnies.Models.Review
#{
Layout = null;
}
#{
if (true)
{
Trigger_Happy_Bunnies.Models.Review newReview = new Trigger_Happy_Bunnies.Models.Review();
<div style="border:1px black">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
and ends with
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
</div>
}
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
And lastly I have this in my controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ReviewCreate([Bind(Include = "Id,BookId,UserId,Text,Title,Rating,IsActive,IsReported,ReportedBy,ReportReason,ModifiedDate,ModifiedBy,CreatedDate")] Review review)
{
if (ModelState.IsValid)
{
db.Reviews.Add(review);
db.SaveChanges();
return View("~/Views/Reviews/ReviewCreate.cshtml");
}
ViewBag.UserId = new SelectList(db.AspNetUsers, "Id", "Email", review.UserId);
ViewBag.BookId = new SelectList(db.Books, "Id", "UserId", review.BookId);
return PartialView();
}
So how can I update the parent view when submitting the form?
I'm not sure what your issue is here. A child action merely dumps its response into the view. So at the end of the day, whether you used a child action, a partial or just plopped the code right in the view, you just have a one HTML document that includes a form.
Calling Html.BeginForm with no parameters says basically that it should use the current action, but even in the context of child action, that's still going to be the main action being rendered. So, your form will post to that main action, not your child action.
That's how it should be. You cannot post to a child action, because that makes no sense in the context of a web page. Technically, you can as long as it's not marked as [ChildActionOnly], but the entire page will change to the partial view that's returned as the response, sans layout. If you want to replace just the area that was rendered via the child action, you must submit an AJAX request that returns the partial response and manually replace the appropriate node in the DOM with that.
In other words, that's why a child action can't redirect. It's not a true action and it hasn't been routed to. It's not rendered until the response preparation phase, and by that point, there's already data in the response, preventing any changes, like a redirect. If you need to redirect after the post of the form, you should have that already in place, just make sure your main action has a version that handles post, and redirect from there.

Categories