I had made a project in ASP.NET to which you can upload, download, delete, and preview files. Whenever I upload them (as an admin) I upload them by category, so that whenever the user is on the site and wants to view a specific file that should be placed in a specific category, he should click that category first to have the specific file displayed. Problem is: when you log in to the site as a normal user, at first, ALL files are displayed, and then, you can choose the category and only the files from that category is displayed. What can I do in case if I want to have all the files displayed back, like in the first instance? For example, to have a "show all" button to press so you can re-see what is displayed at the very beginning, before clicking on any other category.
#model IEnumerable<Proiect2PracticaClona.Models.Files>
<center>
<h1>Suntem fericiti</h1>
<h2>Ca ne merge proiectu</h2>
<hr />
#if (User.IsInRole("Admin"))
{
<form methord="post" enctype="multipart/form-data" asp-controller="Home" asp-action="Index">
<input type="file" name="fifile" />
#Html.RadioButton("category", "incepator")
#Html.RadioButton("category", "intermediar")
#Html.RadioButton("category", "admin")
<input type="submit" value="Upload" />
<hr />
</form>}
<div>
File Name:<input id="search" onkeyup="search()" placeholder="cauta"/>
</div>
<table class="table">
<ul>
<li class="active">#Html.ActionLink("Incepator", "Index", "Home", new { id = "incepator" })</li>
<li class="active">#Html.ActionLink("Intermediar", "Index", "Home", new { id = "intermediar" })</li>
<li class="active">#Html.ActionLink("Admin", "Index", "Home", new { id = "admin" })</li>
</ul>
<tr>
<th>File Name</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#item.info</td>
<td>Download</td>
#if (User.IsInRole("Admin"))
{
<td>Delete</td>
}
</tr>
}
</table>
#section scripts
{
<script>
function search() {
$("tr").each(function (index, value) {
if (index > 0 && !$(this).find("td")[0].innerText.toLowerCase().includes($("#search").val().toLowerCase())) {
$(this).attr("hidden", true);
} else {
$(this).removeAttr("hidden");
}
console.log(value);
})
}
</script>
}
</center>
Related
I have an application that shows a checklist with a dynamic list of tasks. For now all the tasks have 2 radio buttons: one for Done and one for Not Done. I will be adding new task types (textboxes etc.) later.
The main view calls an editor template that creates each task. The checklist model keeps the tasks in a property "Tasks" of type List<Task>. This is fine for display, but has trouble on form submit.
I want to have each task save independently, so I have placed a <form> element around the controls in the editor template.
Controller
public class CheckController : Controller
{
[HttpGet]
public ActionResult Index()
{
var checklist = new Checklist();
GetData(checklist);
return View(checklist);
}
[HttpPost]
public ActionResult Index(Task model)
{
var task = (Task)model;
return Content($"Save Task:{task.TaskId} Value:{task.IsDone}");
}
}
Models
public class Checklist
{
public List<Task> Tasks { get; set; }
public Checklist()
{
Tasks = new List<Task>();
}
}
public class Task
{
public int TaskId { get; set; }
public string TaskName { get; set; }
public bool IsDone { get; set; }
}
Views
#model Checkpoint.Models.Checklist
<table>
#Html.EditorFor(x => x.Tasks);
</table>
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#{
using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => x.TaskId)
#Html.RadioButtonFor(x => x.IsDone, false)<span>Incomplete</span>
#Html.RadioButtonFor(x => x.IsDone, true)<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
}
</td>
</tr>
Rendered HTML
<tr>
<td>First thing</td>
<td>
<form action="/Checklist" method="post">
<input id="Tasks_0__TaskId" name="Tasks[0].TaskId" type="hidden" value="1" />
<input checked="checked"id="Tasks_0__IsDone" name="Tasks[0].IsDone" type="radio" value="False" />
<span>Incomplete</span>
<input id="Tasks_0__IsDone" name="Tasks[0].IsDone" type="radio" value="True"
<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
</form>
</td>
</tr>
<tr>
<td>Second thing</td>
<td>
<form action="/Checklist" method="post">
<input id="Tasks_1__TaskId" name="Tasks[1].TaskId" type="hidden" value="2" />
<input checked="checked" id="Tasks_1__IsDone" name="Tasks[1].IsDone" type="radio" value="False" />
<span>Incomplete</span>
<input id="Tasks_1__IsDone" name="Tasks[1].IsDone" type="radio" value="True" />
<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
</form>
</td>
</tr>
This does submit the request, but the data looks like this:
Tasks[1].TaskId: 1
Tasks[1].IsDone: True
When it reaches the controller action (which accepts type Task), the property values are null.
How can I get my task data correctly in the controller action?
Or am I going about this in the totally wrong way?
Bonus: what would be the best approach for adding the new task types?
Since you're not trying to post the collection all in one submission you'll need to lose the index on the model name.
Tasks[0].TaskId
Adjust your views. The variable name "task" needs to match the action parameter because the HtmlHelpers will generate name attributes based off this string.
#model Checkpoint.Models.Checklist
<table>
#foreach(Task task in Model.Tasks)
{
#Html.EditorFor(m => task)
}
</table>
The rendered html looks something like
<input id="task_TaskId" name="task.TaskId" type="hidden" value="1">
...
The action needs a "task" parameter to match to bind its values
[HttpPost]
public ActionResult Index(Task task)
{
return Content($"Save Task:{task.TaskId} Value:{task.IsDone}");
}
If we use a partial view instead of an editor template we can somewhat relax the name dependency on "task".
#model Checkpoint.Models.Checklist
<table>
#foreach(Task t in Model.Tasks)
{
#Html.PartialView("_TaskForm", t)
}
</table>
And your editor template content will work just the same.
_TaskForm
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#{
using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => x.TaskId)
#Html.RadioButtonFor(x => x.IsDone, false)<span>Incomplete</span>
#Html.RadioButtonFor(x => x.IsDone, true)<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
}
</td>
</tr>
And the rendered html
<input id="TaskId" name="TaskId" type="hidden" value="1">
...
The gotcha with all of the above is the html id attributes will not be unique. So if that's critical you'll need to manually iterate the collection to build each form manually so you can exactly specify the id values. That is, you'd lose the small modular editor templates.
Letting the framework auto-generated "unique" ids... we override the name attribute (mind the capitalization for "Name") we have:
#model Checkpoint.Models.Checklist
<table>
#for(int i = 0; i < Model.Tasks.Count; i++)
{
<tr>
<td>#Model.Tasks[i].TaskName</td>
<td data-ftid="#Model.Tasks[i].TaskId">
#using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => Model.Tasks[i].TaskId, new { Name="TaskId" })
#Html.RadioButtonFor(x => Model.Tasks[i].IsDone, false, new { Name="IsDone" })<span>Incomplete</span>
#Html.RadioButtonFor(x => Model.Tasks[i].IsDone, true, new { Name="IsDone" })<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
</td>
</tr>
}
</table>
I was able to make this work with the Editor Template by dropping the helpers and creating the controls manually.
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
<input name="TaskId" type="hidden" value="#Model.TaskId" />
<input name="IsDone" type="radio" value="True" #Html.Raw(Model.IsDone ? "checked=checked" : null) />
<span>Complete</span>
<input name="IsDone" type="radio" value="False" #Html.Raw(!Model.IsDone ? "checked=checked" : null) />
<span>Incomplete</span>
<button role="button" type="submit" name="taskAction" value="#Model.TaskId">Submit</button>
}
</td>
</tr>
I wasn't overly happy with this and opted instead for #Jasen's partial view solution.
I was able to obtain unique element IDs by overriding the 'id' attribute in the helper.
I used the TaskId since it's unique, but could otherwise have passed in a loop index from the main view.
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => x.TaskId, new { id = "Task_" + Model.TaskId + "_hidIsDone" })
#Html.RadioButtonFor(x => x.IsDone, false, new { id = "Task_"+ Model.TaskId + "_radIsDoneF" })<span>Incomplete</span>
#Html.RadioButtonFor(x => x.IsDone, true, new { id = "Task_" + Model.TaskId + "_radIsDoneT" })<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
</td>
</tr>
I am working on a MVC website and for my delete function I decided to use jQuery UI Dialog to display a popup style dialog box for the user to confirm that they wish to delete the object. My problem is that it is not displaying as intended, when I select to delete I can see my partial view dialog popup for a split second before I am redirected to another page that displays my confirmation message and the button to delete.
This is my delete controller:
//Deletes a selected club
[HttpGet]
public ActionResult DeletePartialView(int? id) //Original: public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Club club = db.Clubs.Find(id);
if (club == null)
{
return HttpNotFound();
}
return PartialView(club);
}
[HttpPost, ActionName("DeletePartialView")]
public ActionResult DeleteConfirmed(int id) //Original: public ActionResult DeleteConfirmed(int id)
{
Club club = db.Clubs.Find(id);
var MembersToDelete = club.ClubMembers.ToList();
foreach (var item in MembersToDelete)
{
db.ClubMembers.Remove(item);
}
db.Clubs.Remove(club);
db.SaveChanges();
return RedirectToAction("Index");
}
This is the Delete button and the partial view in its div:
#Html.ActionLink("Delete", "Delete", new { id = item.ClubID }, new { #class = "btn btn-danger btn-xs" }) |
#*#Html.ActionLink("Delete Partial", "DeletePartialView", new { id = item.ClubID }, new { #class = "btn btn-danger btn-xs" })*#
#Html.ActionLink(
"Delete Partial",
"DeletePartialView",
new { id = item.ClubID },
new
{
#class = "btn btn-danger btn-xs",
id = "deleteClub-opener" //Button ID
})
#* Delete Club Popup*#
<div id="DelteClub-dialog" title="Delete Club">
#Html.Partial("DeletePartialView", new ultimateorganiser.Models.Club())
</div>
This is the jQuery code:
//Delete Club Dialog Window with effects
$(function () {
$("#DelteClub-dialog").dialog({
autoOpen: false,
height: 500,
width: 600,
show: {
effect: "clip",
duration: 500
},
hide: {
effect: "highlight",
duration: 1000
}
});
//Open Delete Club Dialog Window
$("#deleteClub-opener").click(function () {
$("#DelteClub-dialog").dialog("open");
});
})
;
This is how it is currently displaying:
This is what my DeletePartialView looks like:
#model ultimateorganiser.Models.Club
#{
ViewBag.Title = "Delete";
}
<h3 class="text-warning">Are you sure you want to delete this club?</h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-danger" />
#Html.ActionLink("Back to List", "Index")
</div>
}
So far your are good now. To make the delete work add following in your Delete partial view after begin form
<input type="hidden" name="id" value="#Model.Id"/>
please check this code.and tell me another problem for using the dialog box.
only use this library
<html>
<head>
<link href="~/library/jquery-ui.min.css" rel="stylesheet" />
<script src="~/library/jquery.js"></script>
<script src="~/library/jquery-ui.min.js"></script>
</head>
<div>
<button id="btnCreate" class="btn-btn-primary">open the dialog</button>
</div>
<script type="text/javascript">
$(document).ready(function () {
$(function () {
$.noConflict(true);
$("#dialog").dialog({
autoOpen: false,
draggable: true,
resizable: true,
dialogClass: "alert",
modal: true
});
$("#btnCreate").click(function () {
$('#dialog').dialog('open');
});
});
});
<body>
<div id="dialog" style ="display:none" class="form" title="Basic dialog">
<table>
<tr>
<th>Name</th>
</tr>
<tr>
<th>Name</th>
<td><input type ="text" id="txtName" style= "width:200px" />
</tr>
<tr>
<th>Age</th>
<td><input type ="text" id="txtAge" style= "width:200px" />
</tr>
<tr>
<td><input type="submit" value="Create" id="btnCreateId" class="btn btn-Sucess" />
<td><input type="button" value="Cancel" id="txtCancel" class="btn btn-danger"/>
</tr>
</table>
</div>
</body>
<html>
You can use preventDefault in the jQuery binding.
$("#deleteClub-opener").click(function (e) {
e.preventDefault();
$("#DelteClub-dialog").dialog("open");
});
Alternatively, you can also return false in the binding function to prevent event propagation.
I have an ASP.NET project and I have some checkbox to select the recurrence. I want to convert that to a string that will display it.
A simple version is
Create.cshtml
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<p style="font-weight:bold">New Record</p>
<div id="date">
<input type="checkbox" value="Sunday" />Sunday
<input type="checkbox" value="Monday" />Monday
<input type="checkbox" value="Tuesday" />Tuesday
...
</div>
<p>
<input type="submit" value="Create" />
</p>
<div align="left">
<font color="black" size="4" > #Html.ActionLink("<<Back to List", "Index", "Home", null, null)</font>
</div>
</fieldset>
}
And I want to save it in the model as a simple string like "1011011"
Standard Create function
[HttpPost]
public ActionResult Create(Event event)
{
if (ModelState.IsValid)
{
using (var context = new EventDBContext())
{
context.RecordList.Add(event);
context.SaveChanges();
}
return View("Index");
}
return View("Error");
}
What is the proper way to do this?
Utilize the CheckBoxFor Input extension
There are all sorts of walkthroughs on using them.
So in my MVC Orchard application the user chooses a location from a DD & selects a date from a datepicker. Search then looks through the DB table and returns a list of results (if any). User can then use the 'View' button to view each record on screen. This all works fine, however if the user presses the 'back' button, after viewing the record I get the error:
Webpage has expired
I've looked through other examples of GET and POST in my code and I can see no diff. does anyone have any idea why this is happening, think it is something to do with the search, please see code below
#model Project.ViewModels.SearchDeliveryRunsVM
#{
Script.Require("ShapesBase");
Layout.Title = T("Delivery Runs History").ToString();
Script.Require("jQuery");
Script.Require("jQueryUI");
Style.Require("jQueryUI_DatePicker");
}
#using (Html.BeginFormAntiForgeryPost())
{
<div>
<div style="display:inline-block">
<div class="editor-label">Delivery Run</div>
<div class="editor-label">#Html.DropDownList("DeliveryRunId", Model.DeliveryRunList)</div>
</div>
<div style="display:inline-block">
<div class="editor-label">#T("Date")</div>
<div class="editor-label">#Html.TextBoxFor(model => model.SelectedDate, new { #class = "jquery_datepicker", #Value = Model.SelectedDate.HasValue ? Model.SelectedDate.Value.ToString("dd/MM/yyyy") : string.Empty })</div>
</div>
<button style="display:inline-block" type="submit">#T("Search")</button>
</div>
if (Model.Orders != null && Model.Orders.Count() > 0)
{
<br />
<table class="items">
<colgroup>
<col id="Col10" />
<col id="Col11" />
</colgroup>
<tr>
<th>Order Id</th>
<th>Customer</th>
<th>Value</th>
<th>Payment</th>
<th>Signature</th>
<th></th>
</tr>
#foreach (Project.Models.OrderInfo results in Model.Orders)
{
<tr>
<td>#results.OrderRecordId</td>
<td>#results.QbCustName</td>
<td>#results.Value</td>
<td>#results.Payment</td>
<td>#Html.CheckBoxFor(x => results.Signature, new { disabled = "disabled" })</td>
<td>
<div>
#T("ViewOrder")
</div>
</td>
</tr>
}
</table>
}
else
{
if (!Model.IsInitialGet)
{
<p>No records exist</p>
}
}
}
#using (Script.Foot())
{
<script type="text/javascript" language="javascript">
$(function () {
var dates = $("#SelectedDate").datepicker({
dateFormat: 'dd/mm/yy'
}).val("#(Model.SelectedDate.HasValue ? Model.SelectedDate.Value.ToString("dd/MM/yyyy") : DateTime.Now.ToString("dd/MM/yyyy"))");
});
</script>
}
UPDATE
All the other search features on my site are using the Index function of each controller, then in the view using something like:
#using(Html.BeginForm("Index", "CustomerAdmin", FormMethod.Get)) {
<fieldset class="bulk-actions">
<label for="search">#T("Search:")</label>
#Html.TextBoxFor(m => m.SearchExpression)
<button type="submit">#T("Search")</button>
#T("Clear")
</fieldset>
}
to use the GET to display the results, where as my problem I am using GET and POST. perhaps?
It is normal that a page created by a POST action expires after the page is navigated away from; you wouldn't, for example, want the back button to trigger a second credit card charge attempt... You could try using output caching
I'm new to MVC Razor.
I have this view:
#model SuburbanCustPortal.Models.CustomerModel
#{
ViewBag.Title = "Customer Summary";
}
<h2>Customer Summary Screen</h2>
<p>
Please select an account below or add an existing account.
</p>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true, "Account creation was unsuccessful. Please correct the errors and try again.")
<div>
<fieldset>
<legend>Existing Accounts</legend>
#Html.Action("ExistingAccounts2")
<p>
<input type="submit" value="Add an Account" />
</p>
</fieldset>
</div>
}
Which calls this method:
[Authorize]
public ActionResult ExistingAccounts2()
{
return PartialView("ExistingAccounts", _client.RequestCustomersForAccount(User.Identity.Name));
}
Which in turn calls this partial view:
#model IEnumerable<SuburbanCustPortal.SuburbanService.CustomerData >
<br />
<br />
<table>
#if (Model != null)
{
foreach (var usr in Model)
{
<tr>
<td>
<input id="btnShowCustomer" name="btnShowCustomer2" type="submit" value="View"/>
</td>
<td>
#usr.AccountId
</td>
<td>
#usr.Name
</td>
#* <td>
#usr.DeliveryStreet
</td>*#
</tr>
}
}
</table>
<br />
Which ends up displaying this:
This works up to this point.
What I want to so is be able to click on the button next to the customer's name and it pull up the customer's account.
How do I tie that customer to the button to know who to pull up and how do have the button click pull it up?
You need to pass the Customer Number back once the button is clicked:
If you have the customer number as a property in the Model you could do something like:
<input id="btnShowCustomer" data-customerNumber="#usr.CustomerNumber" />
You could then POST this data to the Server using an #Html.ActionLink, #Ajax.ActionLink, or jQuery:
Action Link
#Html.ActionLink("LoadInfo", "Info", new {customerId=#usr.CustomerNumber})
jQuery
$("#btnShowCustomer").click(function() {
var customerId = $("#btnShowCustomer").attr("data-customerNumber");
$.ajax({
type: "POST",
data: "customerId=" + customerId,
url: '#Url.Action("MyAction", "MyController")',
success: function (result) {
}
});
I think this would do the trick ! oid would be the id of the customer (i dont think the path is ok :) )
#Ajax.RawActionLink("Action", "Controller", new { oid = '#Model.customerID'}, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "the view you want to show" }, new { id = "btnNewB", #class = "your btn class" })
good luck ;)