How to pass a model through a MVC controller to a bootstrap modal
I have been working on this for a while and i think i am close. I am trying edit MVC applicationUsers with a bootstrap modal. I am using Angular for the binding, When I click on the User the id is being passed to the Angular controller then to the MVC controller. I thought I could post to the Edit Action in the controller and return the modal with the model. I can not get that work. I created a Action for the modal and it opens just fine. But there is no model attached. How can I can I make this work?
Angular
$scope.editUser = function (id) {
var modalInstance = $modal.open({
templateUrl: 'UsersAdmin/EditUserModal',
controller: $scope.modalEdit,
//matches of the id of your item to recover object model in the controller of the modal
resolve: {
id: function () {
return id
}
}
});
};
//controller of the modal. Inside you can recover your object with ajax request
$scope.modalEdit = function ($scope, $modalInstance, id) {
if (angular.isDefined(id)) {
var reqGetCustomer = $http({ url: '/UsersAdmin/Edit/' + id, method: 'GET' });
reqGetCustomer.success(function (dataResult) {
$scope.model = dataResult;
});
} else { alert('id is undefined'); }
//function to close modal
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
}
}
View with List of Users
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.FullName)
</td>
<td class="text-left" style="width:225px">
@Html.ActionLink("Edit", "Edit", null, new { ng_click = "editUser('" + @item.Id + "')" })
</td>
</tr>
}
</tbody>
MVC controller
public ActionResult EditUserModal(string id)
{
return View();
}
// GET: /Users/Edit/1
public async Task<ActionResult> Edit(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ViewBag.RoleId = new SelectList(RoleManager.Roles, "Id", "Name");
var user = await UserManager.FindByIdAsync(id);
if (user == null)
{
return HttpNotFound();
}
var userRoles = await UserManager.GetRolesAsync(user.Id);
var companies = await _userCompanyService.GetCompaniesAsync();
var selectedCompanies = companies.Where(c => c.Users.Any(u => u.Id == user.Id)).Select(c => c.Id).ToArray();
var model = new EditUserViewModel()
{
Id = user.Id,
UserName = user.UserName,
FullName = user.FullName,
RolesList = RoleManager.Roles.ToList().Select(x => new SelectListItem()
{
Selected = userRoles.Contains(x.Name),
Text = x.Name,
Value = x.Name
}),
CompanyList = new MultiSelectList(companies.Select(c => new
{
Name = c.Name,
Id = c.Id
}),
"Id", "Name", selectedCompanies),
SelectedCompanies = selectedCompanies
};
return View(model);
}
BootstrAP MODAL
@model TransparentEnergy.Models.EditUserViewModel
@{
Layout = null;
}
<div class="modal-header">
<h3 class="modal-title">Edit User</h3>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12">
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
@Html.HiddenFor(model => model.Id)
<div class="card-body card-padding">
<div class="form-group">
<label for="UserName" class="col-md-2 control-label">UserName</label>
<div class="col-md-10">
<div class="fg-line">
@Html.TextBoxFor(m => m.UserName, new { @class = "form-control fg-input" })
@Html.ValidationMessageFor(model => model.UserName)
</div>
</div>
</div>
<div class="col-sm-9">
<div class="form-group fg-line">
<label for="SelectedRoles" class="control-label">Roles</label>
@foreach (var item in Model.RolesList)
{
<input type="checkbox" name="SelectedRoles" value="@item.Value" checked="@item.Selected" class="checkbox-inline" />
@Html.Label(item.Value, new { @class = "control-label" })
}
</div>
</div>
<div class="form-group">
<div class="col-md-2">
<button type="submit" class="btn bgm-blue waves-effect btn-width">Save</button>
</div>
</div>
</div>
}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="modal-footer">
<button class="btn bgm-orange waves-effect btn-width" ng-click="cancel()">Close</button>
</div>
</div>
</div>
the best practice is:
1) Write method in controller (or better if you will write WebApi for pass data to client)
2) Write Angular SERVICE which will work against your API.
3) Write Controller and directives for you page.
the all will very easy. When you need data - you just call your angular service from directive. Anf in view (bootstrap model) you work with your directive properties.
This a little example:
public class DoorsController : ApiContollerBase
{
[HttpGet]
public IEnumerable<DoorViewModel> AdminGetDictionaries()
{
//here i just return List of my doors
return Doors.GetDoors();
}
}
Client side:
Service:
angular
.module('adminApp.services.adminData', ['ngResource'])
.factory('AdminData', ['$resource', 'AppConfig', function ($resource, AppConfig) {
return function (dataName, customActionNames) {
customActionNames = customActionNames || {};
var actions = {
getItem: { method: 'GET', url: AppConfig.apiUrl + 'api/' + dataName + '/' + (customActionNames['getItem'] || 'Test') + '/:id' },
getItems: { method: 'GET', isArray: true, url: AppConfig.apiUrl + dataName + '/' + (customActionNames['getItems'] || 'AdminGet') + '/' },
getItemsForTable: { method: 'POST', url: AppConfig.apiUrl + 'api/' + dataName + '/' + (customActionNames['getItemsForTable'] || 'AdminGetForTable') + '/' },
getDictionaries: { method: 'GET', isArray: true, url: AppConfig.apiUrl + 'api/' + dataName + '/' + (customActionNames['getDictionaries'] || 'AdminGetDictionaries') + '/' },
postItem: { method: 'POST', url: AppConfig.apiUrl + 'api/' + dataName + '/' + (customActionNames['postItem'] || 'AdminPost') + '/' },
putItem: { method: 'PUT', url: AppConfig.apiUrl + 'api/' + dataName + '/' + (customActionNames['putItem'] || 'AdminPut') + '/:id' },
deleteItem: { method: 'DELETE', url: AppConfig.apiUrl + dataName + '/' + (customActionNames['deleteItem'] || 'AdminDelete') + '/:id' },
};
var resource = $resource(AppConfig.apiUrl + dataName + '/:id', null, actions);
return {
getItem: function (id) {
return resource.getItem({ id: id });
},
getItems: function () {
return resource.getItems();
},
getItemsForTable: function (params) {
return resource.getItemsForTable(params);
},
getDictionaries: function (params) {
return resource.getDictionaries(params);
},
createItem: function (item) {
return resource.postItem({}, item);
},
updateItem: function (id, item) {
return resource.putItem({ id: id }, item);
},
deleteItem: function (id) {
return resource.deleteItem({ id: id });
}
}
}
}]);
Directive:
(function () {
'use strict';
angular
.module('adminApp.directives.adminTableArea', ['adminApp.directives', 'adminApp.services'])
.directive('adminTableArea', function () {
return {
restrict: 'E',
replace: true,
templateUrl: '/App/Admin/views/General/admin-table-area.html',
scope: {
options: "="
},
controller: ['$scope', '$translate', 'AdminData', 'DictionaryProvider', '$state', '$window',
function ($scope, $translate, AdminData, DictionaryProvider, $state, $window) {
var vm = this;
var data = AdminData(vm.dataSource, vm.dataActionNames);
....etc...
I hope its will help you.
Good luck. Regards, David
Finally got it figured out in the simplest way possible. no custom MVC helpers or unnecessary jquery.
Here is the Index View with the table
<div class="table-responsive">
<table class="table table-vmiddle">
<thead>
<tr>
<th>Full Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.FullName)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td class="text-left" style="width:100px">
@Html.ActionLink("Edit", "Edit", new { id = item.Id }, new { @class = "btn bgm-gray waves-effect edit" })
</td>
<td class="text-left" style="width:100px">
@Html.ActionLink("Delete", "Edit", null, new { ng_click = "deleteUser('" + @item.Id + "')", @class = "btn" })
</td>
</tr>
}
</tbody>
</table>
</div>
here is the angular controller
$('a.edit').on('click', function () {
$.ajax({
url: this.href,
type: 'GET',
cache: false,
success: function (result) {
$('#myModal').html(result).find('.modal').modal({
show: true,
backdrop: false
});
}
});
return false;
});
$scope.deleteUser = function (id) {
ApplicationUserDelete.remove(id).success(function (result) {
}).error(function (err, result) {
console.log(err, result);
});
};
MVC controller action returning PartialView
// GET: /Users/Edit/1
public async Task<ActionResult> Edit(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ViewBag.RoleId = new SelectList(RoleManager.Roles, "Id", "Name");
var user = await UserManager.FindByIdAsync(id);
if (user == null)
{
return HttpNotFound();
}
var userRoles = await UserManager.GetRolesAsync(user.Id);
var companies = await _userCompanyService.GetCompaniesAsync();
var selectedCompanies = companies.Where(c => c.Users.Any(u => u.Id == user.Id)).Select(c => c.Id).ToArray();
var model = new EditUserViewModel()
{
Id = user.Id,
UserName = user.UserName,
FullName = user.FullName,
RolesList = RoleManager.Roles.ToList().Select(x => new SelectListItem()
{
Selected = userRoles.Contains(x.Name),
Text = x.Name,
Value = x.Name
}),
CompanyList = new MultiSelectList(companies.Select(c => new
{
Name = c.Name,
Id = c.Id
}),
"Id", "Name", selectedCompanies),
SelectedCompanies = selectedCompanies
};
return PartialView(model);
}
Partial Modal View
@model TransparentEnergy.Models.EditUserViewModel
@{
Layout = null;
}
<div class="modal fade" tabindex="-1" role="dialog" aria- labelledby="myModalLabel" data-ng-controller="ApplicationUserController">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Edit User</h4>
</div>
<div class="modal-body margin-top30px">
<div class="row">
<div class="col-md-12">
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
@Html.HiddenFor(model => model.Id)
<div class="z-depth-1 padding20 background-white">
<div class="card-body card-padding">
<div class="form-group margin-bottom10px">
<label for="FullName" class="col-md-2 control-label">Full Name</label>
<div class="col-md-10">
<div class="fg-line">
@Html.TextBoxFor(m => m.FullName, new { @class = "form-control fg-input" })
@Html.ValidationMessageFor(model => model.FullName)
</div>
</div>
<td> </td>
</div>
<div class="form-group margin-bottom10px">
<label for="UserName" class="col-md-2 control-label">Email</label>
<div class="col-md-10">
<div class="fg-line">
@Html.TextBoxFor(m => m.UserName, new { @class = "form-control fg-input" })
@Html.ValidationMessageFor(model => model.UserName)
</div>
</div>
<td> </td>
</div>
<div class="form-group margin-bottom10px">
<label for="SelectedRoles" class="col-md-2 control-label">Roles</label>
<div class="col-md-10">
@foreach (var item in Model.RolesList)
{
<label class="checkbox checkbox-inline m-r-20">
<input type="checkbox" name="SelectedRoles" value="@item.Value" checked="@item.Selected" />
<i class="input-helper"></i>
@Html.Label(item.Value, new { @class = "control-label" })
</label>
}
</div>
<td> </td>
</div>
<div class="form-group margin-bottom10px">
<label for="SelectedCompanies" class="col-md-2 control-label">Companies</label>
<div class="col-md-10">
<div class="fg-line">
@Html.ListBoxFor(model => model.SelectedCompanies, Model.CompanyList, new { @class = "form-control" })
</div>
</div>
<td> </td>
</div>
<div class="form-group" style="margin-bottom:60px">
<div class="col-md-2">
<button type="submit" class="btn bgm-blue waves-effect btn-width">Save</button>
</div>
</div>
</div>
</div>
}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="modal-footer">
<button class="btn bgm-orange waves-effect btn-width" data-dismiss="modal">Close</button>
</div>
</div>
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
</div>
</div>
</div>
The View model was untouched in regards to any of this. hopefully this helps someone. cant believe there isnt a streamlined way to do this!
链接地址: http://www.djcxy.com/p/59768.html上一篇: ASP.Net Async MVC控制器函数导致Razor View Engine错误
下一篇: 如何将模型通过MVC控制器传递给引导模式