I am trying to add a remove/delete a dynamically created partial view.
This is my ADD script.
$("#btnAdd").on('click', function () {
$.ajax({
async: false,
url: '/Employees/Add'
}).success(function (partialView) {
$('#AddSchedule').append("<tbody>" + partialView + "</tbody>");
});
});
this is the add controller
public ActionResult Add()
{
var schedViewModel = new FacultySchedViewModel();
return PartialView("~/Views/Employees/_DynamicView.cshtml", schedViewModel);
}
this is the partial view _DynamicView.cshtml
#using(Html.BeginCollectionItem("New")){
<td>
#Html.ActionLink("Delete", "DeleteThis", "MyController", null)
</td>
<td>
#Html.EditorFor(model => #Model.Schedule, new { htmlAttributes = new { #class = "form-control" } })
</td> }
what i can't figure out are
how to get the ID generated by BeginItemCollection
use the ID in a remove script
action on the controller
EDIT
1. How to connect it to a button or a link for removing the row
Added the view on the the Main of the partial view
#for (int i = 0; i < #Model.New.Count(); i++)
{
#Html.EditorFor(model => #Model.New[i])
}
The BeginItemCollection add a Guid as an indexer to the controls name and id attributes. It has no relevance at all to identifying an item to delete. You need add include the value of the property that identifies the FacultySchedViewModel object. Assuming its int ID, then change the partial to include a button and add the ID as a data- attribute
#using(Html.BeginCollectionItem("New"))
{
<tr>
<td><button type="button" class="delete" data-id="#Model.ID">Delete</button></td>
<td>#Html.EditorFor(model => #Model.Schedule, new { htmlAttributes = new { #class = "form-control" } })</td>
</tr>
}
Then your script would be
var url = '#Url.Action("Delete")'; // assumes its in the same controller
$('.delete').click(function() {
var id = $(this).data('id');
var row = $(this).closest('tr');
if (id) { // or if(id == 0) depending if your property is nullable
row.remove(); // the item never existed so no need to call the server
return;
}
$.post(url, { ID: id }, function(response) {
if(response) {
row.remove(); // OK, so remove the row
} else {
// Oops - display and error message?
}
});
});
and the controller
[HttpPost]
public JsonResult Delete(int ID)
{
// Delete the item in the database
return Json(true); // or if there is an error, return Json(null); to indicate failure
}
Side note:
$('#AddSchedule').append("<tbody>" + partialView + "</tbody>"); is
adding a new tbody element for each item. Instead the main view
should include the tbody element and give it the id so its
$('#AddSchedule').append(partialView); or use $('#AddSchedule
tbody')append(partialView);
Does the model your posting back really have a property named New
(as you indicate in the BeginItemCollection method)?
As per your html render, what I suggest to modify your partial view as
From
#Html.ActionLink("Delete", "DeleteThis", "MyController", null)
To
#Html.ActionLink("Delete", "DeleteThis", "MyController", new { hidefocus = "hidefocus" } ) //add custom properties for here, which you can grab at client side or give css here.
Now search the anchor link via jQuery: Find the element with a particular custom attribute
When you get id, you can go parent like $('#id').parent().parent().hide() or empty()
or
As second option, is on click of Delete button call the same controller , but with a parameter to identify delete, so while returning give the null will bind in ajax again with empty string.
Why does Html.ActionLink render "?Length=4"
http://forums.asp.net/t/1787278.aspx?Add+and+remove+partial+views
Related
I'm trying to fill a text area on my MVC view after retrieving a subset of data. I can get the data, but need to update the view with the returned data
Here is the code I have tried:
<div class="box-shadow">
<p>Please select an Area Path and Iteration Path below:</p>
<table>
<tr>
<th>Area Path</th>
<th>Iteration Path</th>
</tr>
<tr>
<td>
#Html.DropDownList("MySpecialAreaPathsList",((List<string>)ViewBag.myAreaPathsList).Select(m => new SelectListItem { Text = m, Value = m }),
null, new { #onchange = "GetAreaPathValue()" })
</td>
<tr>
<td>
<textarea class="text-info" id="txtLog" style="width:1080px;height:200px"></textarea>
</td>
function GetAreaPathValue() {
var selectedElement = document.querySelector('#MySpecialAreaPathsList');
var option = selectedElement.value;
$.ajax({
url: '#Url.Action("GetAreaPathChildren", "MyController")',
type: "GET",
data: { 'areapathText': option },
success: function (data) { $('#txtLog').value(data) }
})
}
Can someone help me with getting the return data from GetAreaPathChildren (the return value is a List but I'd be happy just getting a string (or any value actually)
I'm trying to fill a text area on my MVC view after retrieving a
subset of data. I can get the data, but need to update the view with
the returned data
Well, based on your shared code snippet, I have successfully reproduced your scenario. The reason why your data is not appending to your textarea as expected has pretty obvious reason. If you check your browser console.log you would get below error:
Reason Of Error:
You are using wrong javascript attribute value. Its incorrect. It should be val insteaed of value. Therefore, your code snippet would be
$('#txtLog').val(data.message) instead of
$('#txtLog').value(data)
Complete Solution
Controller:
public class AppendTextAreaController : Controller
{
public IActionResult Index()
{
List<string> MySpecialAreaPathsList = new List<string>();
MySpecialAreaPathsList.Add("C#");
MySpecialAreaPathsList.Add("SQL");
MySpecialAreaPathsList.Add("Asp.net core");
ViewBag.myAreaPathsList = MySpecialAreaPathsList;
return View();
}
[HttpGet]
public JsonResult GetAreaPathChildren(string areapathText)
{
return new JsonResult(new { message = string.Format("Data From Controller and parameter passed: {0}",areapathText) });
}
}
View:
<div class="box-shadow">
<p>Please select an Area Path and Iteration Path below:</p>
<table>
<tr>
<th>Area Path</th>
<th>Iteration Path</th>
</tr>
<tr>
<td>
#Html.DropDownList("MySpecialAreaPathsList",((List<string>)ViewBag.myAreaPathsList).Select(m => new SelectListItem { Text = m, Value = m }),
null, new { #onchange = "GetAreaPathValue()" })
</td>
<tr>
<td>
<textarea class="text-info" id="txtLog" style="width:1080px;height:200px"></textarea>
</td>
</table>
</div>
#section Scripts {
<script>
function GetAreaPathValue() {
alert("Inside Func");
var selectedElement = document.querySelector('#MySpecialAreaPathsList');
var option = selectedElement.value;
$.ajax({
url: '#Url.Action("GetAreaPathChildren", "AppendTextArea")',
type: "GET",
data: { 'areapathText': option },
success: function (data) {
console.log(data);
$('#txtLog').val(data.message)
}
})
}
</script>
}
Output:
Note:
Remember that, if you return your data from controller like this
var message = string.Format("Data From Controller and parameter passed: {0}", areapathText);
return new JsonResult(message);
In that scenario, you should get this data in your view as below:
$('#txtLog').val(data)
You could refer below code snippet as well.
[HttpGet]
public JsonResult GetAreaPathChildren(string areapathText)
{
var message = string.Format("Data From Controller and parameter passed: {0}", areapathText);
return new JsonResult(message);
}
I'm making a post request from on view so that I don't see the parameters on the URL and I can tell it is passing the appropriate parameters to controller for the request but it does not display the appropriate view from that controller.
Calling view
#Ajax.ActionLink("Work1", "NewIndex", "WorkItems",
new
{
eventCommand = "createforrig",
//eventArgument1 = #item.Id,
eventArgument2 = #item.Id
},
new AjaxOptions
{
HttpMethod = "POST"
})
WorkItems Controller method
[HttpPost]
public ActionResult NewIndex(NewWorkItemViewModel vm)
{
vm.IsValid = ModelState.IsValid;
vm.HandleRequest();
if (vm.IsValid)
{
// NOTE: Must clear the model state in order to bind
// the #Html helpers to the new model values
ModelState.Clear();
}
else
{
foreach (KeyValuePair<string, string> item in vm.ValidationErrors)
{
ModelState.AddModelError(item.Key, item.Value);
}
}
return View(vm);
}
Putting a breakpoint on the last Return View(vm) confirms it is being called but the browsers does not update to display the workItems view.
Suggestions on why the browser is not being updated to display the appropriate view.
You're making an ajax post, the newly rendered view is being returned by the server if you were to look in the network console in your browser. Add a success callback. Either assign a callback to handle the response or use the
UpdateTargetId property in your AjaxOptions
#Ajax.ActionLink("Work1", "NewIndex", "WorkItems",
new
{
eventCommand = "createforrig",
//eventArgument1 = #item.Id,
eventArgument2 = #item.Id
},
new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "AjaxSuccess", //handle with callback
UpdateTargetId = "MyElementID" //update html element
})
if you choose to use OnSuccess then in javascript
function AjaxSuccess(data){
//handle response
}
AjaxOptions properties and usage can be found here
EDIT
You could use javascript to submit a form when a link is clicked, put a form somewhere in your code and hide it.
#using (Html.BeginForm("NewIndex", "WorkItems", FormMethod.Post,
new { class = "hidden", id = "postForm" } ))
{
<input type="hidden" name="eventCommand" value="createforrig" />
<input type="hidden" name="eventArgument2" value="#item.Id" />
<input type="submit" value="link text" id="submitForm"/>
}
then change your #Ajax.ActionLink... to
#Html.ActionLink("Work1", "NewIndex", "WorkItems", new { id = "postLink"})
and if you're using jQuery
<script>
$(function(){
$('#postLink').click(function(e)
{
e.preventDefault();
$('#postForm').submit();
});
});
</script>
and don't forget to hide the form in css
.hidden { display:none;}
I have a DropDownListFor that takes data source from controller. Is there a way to update it since i'm adding new values that i want then to be displayed on the same page.
View:
#Html.DropDownListFor(m => m.Id, MyController.GetIds(Model.Id).Select(g => new SelectListItem { Text = g.Text, Value = g.Value }), #Resource.System_Choose, new
{
#class = "form-control selectpicker",
data_live_search = "true"
})
Controller:
public static List<SelectListItem> GetIds(int Id)
{
var retVal = new List<SelectListItem>();
return retVal;
}
Make your View deal with Model that has property of type List<SelectListItem>() and return this property ready to be binded and displayed in DropDown.
There are some ways to achieve the goal,
Use only javascript to append the new value to select options. (If the new value doesn't send to backend)
Ajax and get the new list.
A sample for case 2, we can put the DropDownList to a partialview and use ajax to get the latest DropDownList in the partialview.
Controller :
public ActionResult QueryNewList()
{
return PartialView("~/Views/Home/_urPartialView.cshtml", viewModel);
}
Html:
<div id="myDiv"></div>
Js:
$.ajax({
dataType: "html",
url: "QueryNewList",
success: function (html) {
$("#myDiv").html("");
$("#myDiv").append(html);
}
})
I'm using BeginCollectionItem with MVC 5 for adding and removing rows whenever.
One issue I'm having is with the delete function, I followed an online tutorial
which specified using #divId:first which seems to indicate deleting the first row whenever. This is no good for me, and wouldn't make sense to an end user.
As I'm using BCI I want to delete these from the html DOM so they won't have database Ids.
How do I delete by the Id of the model, this apparently (I think I read somewhere) is automatically generated by BCI?
Delete Function in the main view
$('#deleterow').live('click', function () {
$(this).parents('#newRow:first').remove();
return false;
});
Partial View with rows I want to delete by Id
#model Mvc.Models.Project
#using (Html.BeginCollectionItem("something"))
{
<div id="newRow">
#Html.LabelFor(m => m.Name)
#Html.EditorFor(m => m.Name)
Delete
</div>
}
Update 2
When viewing the rendered html the data-action attribute renders as 0 for all objects so the JQuery can't and won't delete a row/object from the view.
Update
Instead of the check box I want to use the Delete link button, I assume this is possible? Not very familiar with jQuery but it is something I intend to look at, fairly new to MVC too but this is what I have so far:
Main View
<h3>Students</h3>
<div id="newStudent">
#foreach(var Student in Model.students)
{
Html.RenderPartial("_Student");
}
</div>
<input type="button" id="addStudent" name="addStudent" value="Add Student"/>
<input type="submit" value="Submit"/>
#section Scripts
{
<script type="text/javascript">
$('#addStudent').on('click', function () {
$.ajax({
async: false,
url: 'School/AddNewStudent'
}).success(function (partialView) {
$('#newStudent').append(partialView);
});
});
$('#newStudent').on('click', '.deleteStudent', function () {
var id = $(this).data('id');
if (id === 0) { // assumes Id is integer
$(this).closest('.studentRow').remove();
}
else { // existing item - controller to delete from Db
var url = '#Url.Action("action", "controller")';
$.post(url, { ID: id }, function (response) {
if (response) {
$(this).closest('.studentRow').remove();
}
}).fail(function (response) {
// display error message
});
}
});
</script>
}
Partial View
#using (Html.BeginCollectionItem("students"))
{
<div id="studentRow">
#Html.HiddenFor(m => m.Id)
#Html.LabelFor(m => m.Name)
#Html.EditorFor(m => m.Name)
Delete
</div>
}
Controller
public class SchoolController : Controller
{
// GET: School
public ActionResult Index()
{
var newSchool = new School();
return View(newSchool);
}
public ActionResult AddNewStudent()
{
var student = new Student();
return PartialView("_Student", student);
}
[HttpPost, ActionName("DeleteStudent")]
public ActionResult DeleteStudent(School school)
{
foreach(var student in school.students.Where(s => !s.isDeleted))
{
return View(school.students);
}
return View();
}
}
What I have done is created a IsDeleted Property in Model/ViewModel, Put it in the Row as a Hidden Field, And also have a delete button against each Row
using (Html.BeginCollectionItem("Contacts"))
{
<div class="row mt-10">
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.isDeleted, new { data_is_deleted = "false" })
.......Removed HTML
<div class="col-md-1">
<span class="glyphicon glyphicon-trash" data-action="removeItem" title="remove" style="cursor:pointer"></span>
</div>
Then add this jQuery a JavaScript file. (Note: Don't add this to the Row Partial View, I add it in the View that calls the Row Partial View)
You might have to edit this jQuery to match your HTML structure, The goal in this jQuery is to update the IsDeleted field to either true or false and then Disable the other Input fields
$(document).on('click', '*[data-action="removeItem"]', function(e){
e.stopPropagation();
var btn = $(this);
var row = btn.closest('.row');
var parent = btn.parent();
var checkBox = parent.siblings('*[data-is-deleted]');
var checkBoxVal = checkBox.val();
if(checkBoxVal == 'False' || checkBox.val() == 'false'){
checkBox.val('true');
row.find('input, textarea, select').attr('readonly', 'readonly');
} else {
checkBox.val('false');
row.find('input, textarea, select').attr("readonly", false);
}
checkBoxVal = checkBox.val();
});
This is what your view will look like:
When post Back to Controller:
foreach (var contact in contacts.Where(s => !s.isDeleted))
{
// New and Updated Items
}
foreach (var contact in myModel.Where(s => s.isDeleted && s.Id!= 0))
{
// Deleted Items
// You don't have to delete Items where Id == 0, Bcz they are not in the DB.
// Just some Item added to the View and then deleted without Save
}
Deleted Items will be disabled: Note: You can Hide them by editing the above jQuery
EDIT A:
Actual controller code is something like this:
[HttpPost]
public ActionResult SaveStudent(Student model){
// Save model items
// Then Save the List of Items like this:
foreach (var contact in model.myListItems.Where(s => !s.isDeleted))
{
// New and Updated Items
}
foreach (var contact in model.myListItems.Where(s => s.isDeleted && s.Id!= 0))
{
// Deleted Items
// You don't have to delete Items where Id == 0, Bcz they are not in the DB.
// Just some Item added to the View and then deleted without Save
}
}
Firstly .live() was depreciated in jquery-1.7 and removed in 1.9. Use .on() instead. Next your generating invalid html by generating duplicate id attributes for the 'delete' link, which also means you will only ever be able to delete the first item and you never be able to delete newly added items because you are not using event delegation. Note also the BeginCollectionItem does not _ automatically generate the models ID_. All it does is add a prefix to the property name which includes an indexer value based on a guid so that the items can be bound to a collection on post back.
The link in your partial partial needs a class name and should store the Id value so it can be easily accessed in the script.
#using (Html.BeginCollectionItem("students"))
{
<div id="studentRow">
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.isDeleted) // not sure what the point of the data- attribute is
#Html.LabelFor(m => m.Name)
#Html.EditorFor(m => m.Name)
Delete
</div>
}
Then your script needs to be (note the id="newStudent" for the enclosing <div> is confusing since you foreach loop is generating the html for existing items)
$('#newStudent').on('click', '.deleteStudent', function() { // use event delegation
var id = $(this).data('id');
if (id == 0) { // assumes property Id is typeof int
// Its a new item so just remove from the DOM
$(this).closest('.studentRow').remove();
} else {
// Its an existing item so call controller to delete it from the database
var url = '#Url.Action(""DeleteStudent", "School")';
$.post(url, { ID: id }, function(response) {
if(response) {
// The student was successfully deleted
$(this).closest('.studentRow').remove();
}
}).fail(function (response) {
// Oops, something went wrong - display error message?
});
}
});
And the controller
[HttpPost]
public JsonResult DeleteStudent(int ID)
{
// delete the student from the database based on the ID and signal success
return Json(true);
}
How to insert a record in MVC4 with Entity Framework?
here is my viewpage:
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.brand_id)
</td>
<td>
#Html.DisplayFor(modelItem => item.brand_name)
</td>
<td>
#Html.ActionLink("ADD", "BrandList", new { item.brand_id })
</td>
</tr>
}
here is my controller code:
public ActionResult BrandList()
{
return View(db.brand.ToList());
}
[HttpPost]
public ActionResult BrandList(int id)
{
lovelist Add_Brand = new lovelist();
Add_Brand.lovelist_member = (int)Session["Member_ID"];
Add_Brand.lovelist_brand = id;
db.lovelist.Add(Add_Brand);
db.SaveChanges();
return RedirectToAction("BrandList");
}
This is what I did so far.
I cannot insert a record to my DB.
There's no any error message. I still cannt insert a record to my DB.
You have 2 actions on your controller called BrandList. The second is decorated with the [HttpPost] attribute meaning that it can only be invoked using the POST verb. But in the code you have shown you have only a hyperlink:
#Html.ActionLink("ADD", "BrandList", new { item.brand_id })
In HTML a hyperlink (anchor) sends GET request. So basically when you click on this link you are invoking the first action which doesn't do any DB saving. If you wanted to invoke the second action using a hyperlink you should rename it (because you cannot have 2 actions with the same name accessible with the same verb) and remove the [HttpPost] attribute from it:
public ActionResult SaveBrandList(int id)
{
lovelist Add_Brand = new lovelist();
Add_Brand.lovelist_member = (int)Session["Member_ID"];
Add_Brand.lovelist_brand = id;
db.lovelist.Add(Add_Brand);
db.SaveChanges();
return RedirectToAction("BrandList");
}
You will obviously need to adapt your view as well:
#Html.ActionLink("ADD", "SaveBrandList", new { item.brand_id })
There's also a possibility to use an AJAX link which would allow you to send a POST request:
#Ajax.ActionLink("ADD", "BrandList", new { item.brand_id }, new AjaxOptions { HttpMethod = "POST" })
You will need to include the jquery.unobtrusive-ajax.js script in your view for this to work. Also since you are using an AJAX call now, there's no need to be redirecting anymore from your POST controller action but simply return some partial view or JSON that could be used on the client to refresh some portion of the page.
You have missed parameter name in id and controllername . please change your action-link to
#Html.ActionLink("ADD", "BrandList","ControllerName", new {id = item.brand_id })