How to pass ID to controller and use it to display data on modal - asp.net

I have passed the UserID to the table as shown in the code:
View
#foreach (var user in Model.RIROUsers)
{
<tr>
<td class="text-center">#(user.FirstName + " " + user.LastName)</td>
<td>View Details</button>
</tr>
}
Modal
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-body">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="form-group col-md-4 col-md-offset-2">
<label for="">* Address</label>
<input type="text" class="form-control input-sm" value="">
<label for="">* Birthday</label>
<input type="text" class="form-control input-sm" value="">
<label for="">* Contact</label>
<input type="text" class="form-control input-sm" value="">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Controller
public ActionResult Index()
{
var vm = new RIROViewModel();
vm.RIROUsers = new List<ResourceViewModel>();
foreach (var user in db_RIRO.sp_GetAllRIRORoster())
{
vm.RIROUsers.Add(new ResourceViewModel()
{
EID = user.EID,
FirstName = user.FirstName,
LastName = user.LastName,
EmployeeType = user.EmployeeType,
ProjectName = user.ProjectName,
JobTitle = user.JobTitle,
Level = user.CareerLevel,
ACNRollOn = user.HireDate,
ManagerName = user.Manager,
LeadName = user.Supervisor,
UserID = user.UserID
});
}
return View(vm);
}
Now when I click View Details I want the details of the user to display on the modal. What would be the best approach on this? I'm thinking of creating another stored procedure to retrieve the User's details and display it on the modal. But how do I do this?
EDIT 1: Changed button to a href=~/Views/RIRO/id=#user.UserID

As Shyju said, use click DOM event to the anchor link to show modal popup. Here are the steps:
1) Put Url.Action with proper controller and action name into href attribute of anchor link, then assign a class name to help identify each link.
<a href="#Url.Action("Details", "User", new { id = user.UserID })"
class="btn btn-xs btn-primary details" data-toggle="modal"
data-target="#exampleModal" data-id="#user.UserID">View Details</a>
2) Handle click DOM event using JS which rather than opening a new window/tab in browser, it should open modal popup instead (by using jQuery.ajax(), jQuery.get() or jQuery.load()):
$('.details').click(function (ev) {
ev.preventDefault(); // this is required
// get target action
var action = $(this).attr('href');
$.get(action, function (data) {
$(this).find(".modal-body").html(data);
$('#exampleModal').modal('show');
});
});
// alternative way
$('.details').click(function (ev) {
ev.preventDefault(); // this is required
// get target action
var action = $(this).attr('href');
$('.modal-body').load(action, function () {
$('#exampleModal').modal('show');
});
});
3) Ensure that target action method returns partial view which will loaded to the modal popup.
public ActionResult Details(int id)
{
var vm = new RIROViewModel();
// do something to retrieve data from DB
return PartialView("_Details", vm);
}
References:
Implementing Bootstrap Modal Popup In MVC Application
How to get anchor text/href on click using jQuery?

Related

the form Http POST doesn't work, only Get work in asp core mvc

I have a Form that should pass data through POST request, but GET request is being used without passing the data and do model binding of asp core, so buz of that the method Registrationp is never reach if the attribute [HttpPost] is in place ;( .
I tried many ways to get over this problem but none if them worked, even though the other forms post the data and bind the model successfully
HTML:
#model Student_Training.Models.File;
<form method="post" asp-controller="Students" asp-action="Registrationp" enctype="multipart/form-data">
<label asp-for="FileRep" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<div class="custom-file">
<input type="file" asp-for="FileRep" name="img" accept="image/*" class="form-control custom-file-input" />
<label class="custom-file-label"> Upload...</label>
</div>
</div>
<div class="form-group">
<button id="Button" type="submit" name="submit" formmethod="post" class="btn btn-secondary btn-sm">
<a asp-action="Registrationp"> Save </a>
</button>
</div>
</form>
Controller POST method:
[HttpPost]
public async Task<IActionResult> Registrationp([Bind("FileId, FileName, OwnerId, FileRep")] Student_Training.Models.File imgFileModel, IFormFile img, int? id)
{
var user = await _userManager.FindByNameAsync(User.Identity.Name);
var userEmail = user.Email;
Student Student = _context.Student.FirstOrDefaultAsync(x => x.Email == userEmail).Result;
// StudentId
id = Student.StudentId;
// Save img to wwwroot/img folder
string wwwRootPath = _hostEnvironment.WebRootPath;
Student_Training.Models.File myFile = new Student_Training.Models.File();
string fileName = Path.GetFileNameWithoutExtension(imgFileModel.FileRep.FileName);
string extention = Path.GetExtension(imgFileModel.FileRep.FileName);
imgFileModel.FileName = fileName = fileName + DateTime.Now.ToString("yymmss") + extention;
string path = Path.Combine(wwwRootPath + "/img/", fileName);
using (var fileStream = new FileStream(path, FileMode.Create))
{
await imgFileModel.FileRep.CopyToAsync(fileStream);
}
// insert recorod to Db
_context.Add(imgFileModel);
await _context.SaveChangesAsync();
return View();
}
As a matter of fact you are using an ancor tag to submit your form, not a submit button. An ancor tag is always generates a GET request. So just remove it from your code:
<button id="submitButton" type="submit" class="btn btn-secondary btn-sm">Save</button>

How do I call my own API from a View? ASP.NET MVC

I have an API that I've created for user registration / authentication, and similar operations. Example post method:
[AllowAnonymous]
[HttpPost("authenticate")]
public IActionResult Authenticate([FromBody]AuthenticateModel model)
{
var user = _userService.Authenticate(model.Username, model.Password);
if (user == null)
return BadRequest(new { message = "Username or password is incorrect" });
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.Id.ToString()),
new Claim(ClaimTypes.Role, user.Role)
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
// return basic user info and authentication token
return Ok(new
{
user.Id,
user.Username,
Token = tokenString,
});
I now need my front-end to implement my API. So I'd like to call this API from a View. For example, say I want to create a simple login page:
<div class="row">
<div class="col-md-12">
<form method="post" action="">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Username"></label>
<input asp-for="Username" class="form-control" />
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password"></label>
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
How would I now call the authenticate post method for this login form? As I have a controller which is the API controller, and I have a controller which is the action controller, for the users.
File structure if needed:
File structure
Calling your own web action can be done in mainly two ways:
Native HTML form submission.
AJAX
Native submit reloads your entire page. And address will be changed to the URL or your web action. Typically used as a search function, like:
<form asp-controller="Search" asp-action="Blogs" method="get">
<input type="text" name="question" />
<input type="submit" />
</form>
When the user submit the form with clicking the submit button, the browser will be redirect to /search/blogs?question=textHeInput.
To prevent page refreshing, you can submit a request with pure JavaScript. Which called AJAX.
https://en.wikipedia.org/wiki/Ajax_(programming)
For example:
// Require jQuery:
$.post('/authenticate', { "yourPropertyName" : "yourPropertyValue" }, function(response) {
// Do something after the request. Access response like this:
alert(response.Username);
});
And server responded username will shown.
You can use ASP.NET MVC Core Tag Helpers:
<form asp-controller="MyControllerName" asp-action="Authenticate" method="post">
<!-- Input and Submit elements -->
</form>
Since you're using JwtBearer with WebAPI's, an assumption is that you're probably going to call your authentication method using Ajax. Unfortunately you did not provide your class declaration showing your route convention for your ApiClass but normally it goes as "api/[Controller]"... If this is the case, you can do the following:
$("submitButton").click(
function authenticateUser()
{
$.post(
'/api/[COntrollerName]/authentication', // URL
$('#form").serialize(), // this is your form data as an object
function(payload) //Response
{
// do something with payload here
}
});
}
);
<button type="submit" class="btn btn-primary" id="submitButton">Login</button>
You might want to set your <button type="button"> so that the form doesn't submit. Attach a click event to that function, so that it processes the api call.

ng-model value becoming null while disabling the selected value in dynamic dropdown list

I have created a process for creating a dynamic dropdown list group on button click with the given number of the dropdown lists in an input field. Then i collect a user list from the database and showing all in these doropdown lists. Now my job is that if one user is selected by any dropdown then that option must be disabled for the others. How can i do that?
I tried that by disabling the selected option from the list, But when i am disabling the selected option, the dropdown ng-model that selected that option is becoming null.
For creating a dynamic Dropdown list:
<div class="col-md-3">
<div class="form-group-sm">
<input class="form-control" ng-model="numberOfLevels"
type="text" name="numberOfLevels" id="numberOfLevels">
</div>
</div>
<div class="col-md-7" >
<div class="form-group-sm">
<a href="#" type="button" class="btn btn-box-tool btn-primary"
style="color:white;"
ng-click="addLevels(numberOfLevels)" >Manage</a>
</div>
</div>
$scope.addLevels = function (num) {
getAllUsers();
$scope.showLevels = true;
$scope.levels = [];
var count = 0;
if (num > 0) {
while (count < num) {
count++;
//console.log(count);
$scope.levels.push({ 'key': count, 'value': count });
//console.log(count);
}
}
//console.log($scope.levels);
//getAllUsers();
$scope.approversInputList = [];
}
<div class="col-md-12" ng-show="showLevels" ng-repeat="a in levels">
<div class="form-group">
<div class="col-md-4">
<label for=" username">
Approver {{a.value}} :
</label>
<select class="browser-default custom-select form-control has-error"
ng-model="abc[a.value]"
ng-change="setApprovers(selectedFileId, selectedNoteSheetId,a.value, abc[a.value])">
<option></option>
<option id="select" ng-repeat="user in userList"
value="{{user.Id}}" ng-disabled="user.Disabled">
{{user.UserName}}
</option>
#*<option id="select" ng-repeat="user in userList"
value="{{user.Id}}"
ng-disabled="disabledList[user.Id]">
{{user.UserName}}
</option>*#
</select>
</div>
<div class="col-md-7">
</div>
</div>
</div>
User List View Model:
public int Id { get; set; }
public string UserName { get; set; }
public bool Disabled { get; set; }
AngularJs Code for Disabling Selected Option:
$scope.abc = {};
$scope.$watch('abc', function (newVal, oldVal) {
//console.log($scope.userList);
var aaa = $scope.approversInputList;
for (var i = 0; i < $scope.userList.length; i++) {
$scope.userList[i].Disabled = false;
//console.log($scope.abc);
angular.forEach($scope.abc, function (value) {
if ($scope.userList[i].Id == value) {
$scope.userList[i].Disabled = true;
//$scope.disabledList[value] = true;
}
});
}
//console.log($scope.disabledList);
}, true);
When the selected option is disabled the dropdown should show the selected username.
This is happening because your userList is only one instance for all select. So you set disabled in userList and it propagates to all the levels.
u can try this, it will be difficult to solve it exactly until u give a minimal reproducible example:
<select class="browser-default custom-select form-control has-error"
ng-model="abc[a.value]"
ng-change="setApprovers(selectedFileId, selectedNoteSheetId,a.value, abc[a.value])">
<option></option>
<option id="select{{$index}}" ng-repeat="user in userList"
value="{{user.Id}}" ng-disabled="abc[a.value] == user.Id">
{{user.UserName}}
</option>
</select>
And remove your for loop altogether. if ng-disabled="abc[a.value] == user.Id" does not work then instead of using ng-diabled use some class if the condition is met and do some css on that class to make it disabled urself.

call mvc controller without post back mvc 5 angularjs

i am creating an asp.net mvc 5 web app(with angularjs)
in my app i am calling a controller to download user pic but the whole page is being refreshed,
and i don't want to postback the particular page
this is how my controller looks
[HttpPost]
public ActionResult profilecompletion(FormCollection fc, HttpPostedFileBase file)
{
// tbl_details tbl = new tbl_details();
var allowedExtensions = new[] {
".Jpg", ".png", ".jpg", "jpeg",".doc",".docx",".pdf",".xlsx",".xls"
};
string id = fc["name"].ToString();
//tbl.Id = fc["Id"].ToString();
//tbl.Image_url = file.ToString(); //getting complete url
//tbl.Name = fc["Name"].ToString();
if (file==null)
{
}
else
{
var fileName = Path.GetFileName(file.FileName); //getting only file name(ex-ganesh.jpg)
var ext = Path.GetExtension(file.FileName); //getting the extension(ex-.jpg)
if (allowedExtensions.Contains(ext)) //check what type of extension
{
string name = Path.GetFileName(id + fileName); //getting file name without extension
//string myfile = name + "_" + "" + ext; //appending the name with id
// store the file inside ~/project folder(Img)
if (!Directory.Exists(Server.MapPath("~/userpic")))
{
Directory.CreateDirectory(Server.MapPath("~/userpic"));
}
var path = Path.Combine(Server.MapPath("~/userpic"), name);
//tbl.Image_url = path;
//obj.tbl_details.Add(tbl);
//obj.SaveChanges();
file.SaveAs(path);
}
else
{
ViewBag.message = "Please choose only Image file";
}
}
return RedirectToAction("Dashboard", "Dashboard");
}
and this is my cshtml page
#using (Html.BeginForm("profilecompletion", "user", FormMethod.Post, new
{
enctype = "multipart/form-data"
}))
{
<div class="row">
<div class="col-sm-8">
<span>Profile Pic</span>
<input id="imagepath" type="file" file-model="profileimage" ng-text-change="changeimage()" name="file" />
</div>
<div class="col-sm-4">
<img id="myImg" src="#" alt="Choose image" style="height:100px; width:100px; border-radius:10px;" ng-hide="hidestat" ng-src="{{image}}" />
#*<input id="imagepath" type="file" file-model="profileimage" class="form-control" />*#
</div>
</div>
<div class="button-container">
<input type="submit" name="Update" class="btn btn-primary" ng-click="update()" title="save" />
</div>
}
the page load is preventing the app to execute update() function properly
what i need to do here to prevent any kind of postback or pageload without effecting any programmability.
The reason why the page reloads is because you are using a submit button which as its name suggests submits the form with a full postback to the server. You could use a regular button instead:
<input type="button" name="Update" class="btn btn-primary" ng-click="update()" title="save" />
Try this
<button type="button" name="Update" class="btn btn-primary" ng-click="update()" title="save" > Submit </button>

Add items to select list on the client side in MVC 5 ASP

I'm trying to learn more about MVC 5 so I'm writing a bloging site for myself to learn more as I go.
I have set up a select list for tags and would like to be able to add new tags from the create blog entry page rather than having to remember to set the tags up before creating a new post. I'm thinking down the lines of a "Add Tag" button which displays a bootstrap modal window where the user can add a new tag.
Here is my controller action:
public ViewResult CreateBlogPost()
{
CreateEditBlogViewModel viewModel = new CreateEditBlogViewModel();
viewModel.BlogPost = new Core.BlogPost();
viewModel.BlogPost.ShortBody = "<p>Something short and sweet to describe the post</p>";
viewModel.BlogPost.Body = "<p>Enter something blog worthy here...</p>";
viewModel.Tags = new SelectList(_blogRepo.BlogTags(), "Id", "Name");
viewModel.Categories = new SelectList(_blogRepo.BlogCategories(), "Id", "Name");
return View(viewModel);
}
And here is the HTML in the view:
<div class="row">
<div class="form-group">
#Html.LabelFor(m => m.BlogPost.Tags, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.ListBoxFor(m => m.SelectedTags, Model.Tags, new { #class = "form-control chosen-select", #data_placeholder = "Start typing to see a list of tags" })
</div>
</div>
</div>
<div class="row">
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#tagModal">
Add Tag
</button>
</div>
Here is my partial view for the modal window:
#using (Html.BeginForm("SaveTag", "Home", FormMethod.Post, new { id = "tag-form" }))
{
#Html.AntiForgeryToken()
<!-- Modal -->
<div class="modal fade" id="tagModal" tabindex="-1" role="dialog" aria-labelledby="tagModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="tagModalLabel">Enter a name for a new tag</h4>
</div>
<div class="modal-body">
<input type="text" id="Name" placeholder="Enter a new tag name" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
}
Is it possible to add a tag on the client side, persist it into the db and then add it to my tags select list without refreshing the page?
PS: FYI I'm using the Chosen multi-select from here.
#section scripts {
<script type="text/javascript" src="~/Scripts/chosen.jquery.min.js"></script>
<script type="text/javascript">
$(".chosen-select").chosen()
</script>
}
EDIT: I have updated the question with all the code that makes the view give the user the modal window to enter a new tag name. I'm just not sure how to post without navigating away from the page so I'm guessing some sort of Ajax post is required. And then what to do with the data that is returned from that post. How do I then add that new persisted record to the select list?
I know the tag isn't passing to the controller method as it's not bound to any sort of model but being as I'm using a view model on the parent view, I'm not sure how I would handle that here either.
In order to dynamically add a new BlogTag in the view you will need to post the new tag Name using ajax, to a controller method that saves the BlogTag and returns its new ID value. Your controller method would be something like
[HttpPost]
public JsonResult CreateTag(string name)
{
BlogTag tag = new BlogTag(){ Name = name };
db.BlogTags.Add(tag);
db.SaveChanges();
return Json(tag.ID);
// If the above code could result in an error/exception, catch it and return
// return Json(null);
}
Then in the view, handle the dialogs submit button to post the value and update the tag list
var url = '#Url.Action("CreateTag")';
var tagList = $('#SelectedTags');
$('#tag-form').submit(function() {
var tagName = $('#Name').val();
$.post(url, { name: tagName }, function(id) {
if (id) {
// add the new tag to the list box
tagList.append($('<option></option>').val(id).text($('#Name').val()));
// trigger the chosen update
tagList.trigger("chosen:updated");
} else {
// Oops - display an error message?
}
}).fail(function (result) {
// Oops - display an error message?
});
return false; // cancel the default submit
});
Side note: I would recommend that you create a view model for BlogTagVM (containing a property for the Name with validation attributes) and an associated partial view (say _AddBlogTag.cshtml) that generates the dialog html, so that in the main view you can use #Html.Partial("_AddBlogTag", new BlogTagVM()) which will allow you to use the strongly typed html helpers, and to include client side validation.
Note also that nested <form> elements are invalid html so ensure that html for the dialog is outside the main <form> tag for the view.
I am doing something similar, I think it might help. In my case, I'm "moving" values from one list to another (from "available" to "used") and then saving the values of the "used" list. Anyway, in the controller, the "used" list shows up as an array of strings. Here's my code:
public ActionResult PinchHit(FormCollection form, LineupViewModel lvm, String[] UsedPlayers)
{
[Snip]
if (ModelState.IsValid && lineupResults.IsValid)
{
[Snip]
foreach (String usedID in UsedPlayers)
{
gameState.HomeUsedPlayersIDs.Add(Convert.ToInt32(usedID));
}
uow.Repository<GameState>().Update(gameState);
uow.SaveChanges();
return RedirectToAction("Index", "GameSummary");
}
[Snip]
return View(lvm2);
}
Hope that helps.
Per my comment:
Here is an AJAX call-back mechanism I used to retrieve data from the database without reloading the page, you could use it to save data to the database instead.
<script type="text/javascript">
function getPositions(id, control) {
$.ajax({
url: "#Url.Action("GetPositions", "Lineup")",
data:
{
id: id
},
dataType: "json",
type: "POST",
error: function () {
alert("An error occurred.");
},
success: function (data) {
$(control).html("");
$.each(data, function (i, item) {
$(control).append("<option value=\"" + item.Value + "\">" + item.Text + "</option>");
}
);
}
});
}
</script>
then in the controller:
[HttpPost]
public ActionResult GetPositions(int id)
{
Player player = uow.Repository<Player>().GetById(id);
if (player == null)
{
return (null);
}
List<SelectListItem> positionList = new SelectList(player.Positions, "ID", "ShortName").ToList();
return Json(positionList);
}
Pretty standard stuff really.

Resources