CRUD, create and update functionality on same view : ASP.net MVC2 + EF - asp.net-mvc

I am a newbie and is making web application in Visual Studio 2010 using MVC2 + Entity framework.
I have a situation in which I want to put both operations i.e create user / update user at same view, I have also tried attaching relevant picture where I have made two portions one for create user and second for manage users.
My 'create user' fields are at top of website and when user click 'create button' page got refreshed and all enlisted users gets displayed on same view under second portion 'manage users' showing link to edit/delete them.
I want that when I click on edit link, that particular entity fields get populated on same view in first portion 'create user' where I can modify them and press 'update button'
VIEW
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Admin.Master" Inherits="System.Web.Mvc.ViewPage" %>
<%# Import Namespace="MyNamespace" %>
<h4>Create New User</h4>
<form method="post" action="/Lignum/CUser">
<label for="inputEmail3">Full Name</label>
<input type="text" name="Fullname" id="txtFullname" >
<label for="inputEmail3">Email</label>
<input type="email" name="Email" id="Email1">
<button id="btnCUser" class="btn btn-primary">Create</button>
</form>
<h4>Manage Users</h4>
<table>
<tr>
<td>Sr#</td><td>Name</td><td>Email</td><td></td>
</tr>
<% int i=0;
foreach (MyWebsite.Models.User objUser in ViewData.Model as IEnumerable<MyWebsite.Models.User>)
{%>
<tr>
<td><%= ++i%></td>
<td><%= objUser.Fullname%></td>
<td><%= objUser.Email%></td>
<td>
Edit
</td>
</tr>
<%}%>
</table>
CONTROLLER
public ActionResult Index()
{
return View("UserMgt", _repositoryUser.SelectAll());
}
public ActionResult Edit(object Id)
{
if (Id != null && Id.ToString().Trim().Length > 0)
{
int param = int.Parse(Id.ToString());
return View("UserMgt", _repositoryUser.SelectByID(Id));
}
return View("404");
}

You will need to make use of JQuery & Ajax to achieve this. Your page is getting refreshed most likely because your are submitting a form. Instead of form submit, you need to attach a function to handle onclick event.
In that function you will know which item is clicked, load the data to be edited from the server sending an ajax request with item id.
When request return you can then open a JQuery popup window or update page's html to display data. User will be allowed to make changes and on Ok button click you can again send the data back to server to save.
I am looking for an example online to refer to you as my code is little complex. You can also look for an example online.
UPDATE:
i want that when i click on edit link, that particular entity fields
get populated on same view in 1st portion 'create user' where i can
modify them and press 'update button'
Ok, looked at your code. As I said earlier you will need to define an "id" for each html element, the value will be objUser.UserId (you can prefix something if you want). Now define a click event for all html elements i.e. .
For a working example refer this link.
I suggest you progress as you gain some insight and post updated code. We will suggest what's needed for next step. This way you would learn more.

You can try following:
Create a View model with whatever you need on the create page i.e. user details
strongly bind your view with this view model
Have three action methods in controller "Create","Populate" and "Update" with Update and Populate taking Id of the entity as input (you can choose better names)
Initially call Create method which will just return an empty view model with your View
Have a hidden variable in view which will store the Id of the entity (in case of create this will be zero)
on click of create just take the value of this hidden variable and do a post to Update action method.In this case if it is new entity id will be zero
On click of edit go call Populate method with id of the entity which again will return ViewModel with entity details loaded to the same create view (also set the hidden variable with id)
In your update method based on the id perform create or update operation i.e. Create for zero and Update for 1
If you post your code or other details I can give some more details using code.
EDIT: OK few more details in terms of code.
//This is the view model you need to bind to your view
public class UserViewModel
{
public int UserId { get; set; }
public string Email { get; set; }
public string FullName { get; set; }
public List<Users> UserList {get;set;} //For binding to the grid
}
Below are the action methods in controller.
public ActionResult Create()
{
var viewModel = new UserViewModel();
//Logic: Create empty view model for create
return View("UserMgt", viewModel);
}
public ActionResult Edit(int id)
{
var viewModel = new UserViewModel();
//Logic: populate the view model based on the id
return View("UserMgt", viewModel);
}
// Call this method using Jquery ajax
public bool Update(UserViewModel user)
{
if (user.Id == 0)
//Logic : Create the user
else
//Logic : Edit the user
return Json(status); //Status = true if successful else false
}
Initially call create.On click of edit call Edit method.On click of save call Update.
For using jquery ajax follow below link
http://api.jquery.com/jquery.ajax/

Related

Profile Image in AspNet Identity

In my application I want to show user profile image in layout page (_LoginPartial).
In AspNet Identity membership their is a AspNerUser table . I want to customize this AspNerUser table to maintain image field.
then show that image in Layout page (_LoginPartial) view.
How can I do this ? Really appreciate can suggest a way to do this
EDIT
I generated my DataBaseContext name using ADO.NET entity model , database Context name is ProjectNameEntities
then I tried to enable migration using following command on PMC
Enable-Migrations -ContextTypeName myProject.Models.ProjectNameEntities
but then I'm getting following error
Creating a DbModelBuilder or writing the EDMX from a DbContext created
using Database First or Model First is not supported. EDMX can only be
obtained from a Code First DbContext created without using an existing
DbCompiledModel.
is this possible to do with edmx model ?
Add Field Model (Code First)
First thing you need to do is modify the ApplicationUser Model that the database table is built from. This class is usually located in the IdentityModels.cs file. Add a new field to hold the image:
public class ApplicationUser : IdentityUser
{
// maybe be other code in this model
public byte[] ProfilePicture { get; set; }
}
Next you need to update your database to reflect the changes (assuming you are using Code First). You can find detailed information on the process in this article.
Enable-Migration
Add-Migration "Added user profile"
Update-Database (will apply any pending migrations to the database)
Return profile picture
Now add an action to a controller similar to:
public FileContentResult Photo(string userId)
{
// get EF Database (maybe different way in your applicaiton)
var db = HttpContext.GetOwinContext().Get<ApplicationDbContext>();
// find the user. I am skipping validations and other checks.
var user = db.Users.Where(x => x.Id == userId).FirstOrDefault();
return new FileContentResult(user.ProfilePicture, "image/jpeg");
}
Finally in your _LoginPartial add the following call to the Action we just created where ever you want the image to show up. You will need to change the Controller name to what ever controller you put your action on.
<img src="#Url.Action("Photo", "Account" , new { UserId=User.Identity.GetUserId() })" />
Save profile picture
First you need to create a page to upload the image. Create an action to return the form:
[HttpGet]
public ActionResult Profile()
{
ViewBag.Message = "Update your profile";
return View();
}
The Razor view would be called Profile.cshtml and look have a form on it that looks like: (note that the Action and controller location may be different for you depending on how you structure your project)
#using (Html.BeginForm("Profile", "Manage", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<fieldset>
<legend>Photo</legend>
<div class="editor-label">
<label for="profile">FileName:</label>
</div>
<div class="editor-field">
<input name="Profile" id="profile" type="file" />
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
The form will post back to an action so you need to create one that looks like:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Profile(HttpPostedFileBase Profile)
{
// get EF Database (maybe different way in your applicaiton)
var db = HttpContext.GetOwinContext().Get<ApplicationDbContext>();
// find the user. I am skipping validations and other checks.
var userid = User.Identity.GetUserId();
var user = db.Users.Where(x => x.Id == userid).FirstOrDefault();
// convert image stream to byte array
byte[] image = new byte[Profile.ContentLength];
Profile.InputStream.Read(image, 0, Convert.ToInt32(Profile.ContentLength));
user.ProfilePicture = image;
// save changes to database
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
Note that there needs to be validations and checks put in place according to your rules but this is the basic idea on how it works.
Created a GitHub project that shows the basics above in a working sample: https://github.com/jsturtevant/mvc-aspnet-identity2-profile-picture-sample

Partial View submit returns null

I'm trying to create a single view which allows the user to see the currently listed items using the index view model and then also allows the user to create a new item using a seperate create view model
So I've got two viewModels
-IndexFunkyThingsViewModel
-CreateFunkyThingViewModel
In essence I've got a main view:
#model IndexFunkyThingsViewModel
#foreach (var item in Model.FunkyThings)
{
/*Indexy stuff*/
}
/*If create item*/
#if (Model.CreateFunkyThing)
{
#Html.Partial("_CreateFunkyThingPartial", new CreateFunkyThingViewModel());
}
Then in my partial view I have
#model CreateFunkyThingViewModel
#using (Html.BeginForm(MVC.FunkyThings.CreateFunkyThing(Model)))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Create FunkyThing</legend>
#Html.EditorForModel();
<p>
<input type="submit" class="button green" value="CreateFunkyThing" />
</p>
</fieldset>
}
Finally in the controller I have:
[HttpPost]
public virtual ActionResult CreateFunkyThing(CreateFunkyThingViewModel createFunkyThingViewModel)
{
..
}
This all seems to compile happily and when I go to the view it works so far as displaying the create fields and such like. However when I then hit the submit button the controller receives no data. The ActionResult is called however in the debugger the createFunkyThingViewModel parameter is null when called by the submit button.
What am I doing wrong?
When posting to your controller, you're not sending the model down to it. Use this:
#using (Html.BeginForm("CreateFunkyThing", "ControllerName", FormMethod.Post))
then remove the p tags from around the button, and don't use anything with it.
The paragraph tags have a tendency to group the button separately from a form even if they are in the same outer container.

asp.net mvc ViewModel in a View with List of objects has old list items displayed after removing in controller

I have poked around but not found out what the ViewModel, or TempData or how my objects are being persisted for my form.
I display a custom view model in an asp.net MVC view, I edit a list of objects in that view and display them all inside a dynamic grid inside an html form, then submit the changes. When I get back to the controller I check existing objects vs the forms submitted object list and update the objects.
When I redisplay the form, objects that were deleted still show up and have values in the textbox inside the html elements, so it is asp popluating the fileds and not a browser cache. I have a checkbox that displays next to the row if it is an existing object already and those checkboxes are submitted to the controller as an array of values (the id of the object to remove).
So I delete the object, pull clean ones out of the database and set the list in the viewmodel with the newly retrieved data. However, the form shows the old object still, but there is no delete checkbox next to them so they were not retrieved from the database.
How do I fix that? I tried tweaking the methods output cache (not a browser issue as the DB ID key does not exists anymore ... no delete checkbox). I tried making a new view model an explicitly setting variables before sending to the view...no go.
My solution for now was to redirect to the get method after I edit all of the objects (simpleObject in the example) and start completely over.
A simplified example is as follows:
public class CustomViewModel {
List<SimpleObject> objects {get;set;}
}
public class SimpleObect {
public int iA {get;set;}
public int AddonHistID {get;set;}
}
Controller:
[HTTPGet] // get method and displays 2 objects by default
public ActionResult whatever( string something){
CustomViewModel form = new CustomViewModel ();
form.objects = new List<SimpleObject>();
form.objects.Add( new SimpleObect());
form.objects.Add( new SimpleObect());
return View( form)
}
[HttpPost]
public ActionResult whatever( string something, CustomViewModel form){
// adjust objects to show current objects aftering saving changes (reload and rebind to ModelView)
form.objects = getObjectsAfterChange( something); // just gets objects from db after all changes are made in this controller action
return View( form);
}
View:
<% using( Html.BeginForm()) { %>
<table width="800" id="SearchAddonsResults">
foreach( SimpleObject addonHist in Model.objects )
{
++iOdd;
string cssClass = (iOdd % 2 == 0 ? "rowOdd" : "rowEven");
%>
<tr class="<%= cssClass %>">
<td>
<%if (addonHist.AddonID > 0)
{ %>
<input type="checkbox" name="RemoveAddon" id="RemoveAddon" value="<%= addonHist.AddonID.ToString() %>" />
<% } %>
<%= addonHist.AddonHistID.ToString() %>
</td>
<td><%= addonHist.iA.ToString() %></td>
</tr>
<% } %>
</table>
<% }; //endform %>
I think this might help you get the results you expect.
Phil Haack's Blog:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Which is linked to from:
How to model bind to a List<ViewModel>?
Complex model binding to a list
How ASP.NET MVC: How can I bind a property of type List<T>?
So I delete the object, pull clean ones out of the database
and set the list in the viewmodel with the newly retrieved
data. However, the form shows the old object still,
This makes no sense. Are you absolutely sure that this line
form.objects = getObjectsAfterChange( something);
in your HttpPost method is retrieving the right information?
I would start by inspecting the value that getObjectsAfterChange( something) is returning . I suspect it's returning more than you think and that's where the problem is (rather than on the render of the view.)

MVC3 - Submission of custom input attributes on input button when submitting a form

Basically I have a form that I am dynamically adding objects to. I am doing this with AJAX so can just initialise the object and return it with JSON. Each new object has a unique GUID assigned to it so we can identify each object in the model collection when it is passed back into the action.
However, I need to support non JavaScript so am trying to write a solution that will post back the model and add or remove the given object from the model. There can be any number of these new objects on the model so I need to pass back several things to find out which object to delete before returning the model back to the view. This could be either
a) The GUID for the object the user has deleted.
b) The button that has been clicked to identify which object to delete.
The problem is that the partial view is generic and I would like to keep it that way so I'm trying to pass the identifying GUID back with the input button on each partial view but don't know how. I can easily do this with JavaScript because I just remove the created AJAX object from the page before posting it when the user clicks the remove link but can't figure out how to do it with a submit. Basically I want to do something like this:
#using (Project.Namespace.Infrastructure.Helpers.HtmlPrefixScopeExtensions.HtmlFieldPrefixScope _scope = Html.BeginCollectionItem())
{
<ul class="ulMedicationsControl">
#Html.ActionLink("Remove This Object", "RemoveObject", null)
#Html.Input("RemoveObject", "Remove This Object", new { Prefix = _scope.Prefix, objectGUID = IdentifyingGUID })
#Html.HiddenFor(m => m.IdentifyingGUID);
<li class="liQuestion">
#Html.MandatoryLabelFor(m => m.myField)
#Html.TextBoxFor(m => m.myField)
</li>
</ul>
<div id="#(_scope.Prefix).ajaxPlaceholder"></div>
}
In the controller:
[ActionName("FormName")]
[AcceptParameter(Name = "RemoveObject", Value = "Remove This Object")]
public ActionResult RemoveObject(MyParentModel model, string Prefix, string objectGUID)
{
Guid ID = new Guid(objectGUID);
foreach (ObjectModel object in model.objects){
if (object.IdentifyingGUID == ID)
{
model.objects.Remove(object);
break;
}
}
return View(model);
}
Any help I would really appreciate as I simple can't figure out how to do this!
EDIT
Also just to add the prefix attribute simply identifies where in the form the object sits. This will be needed for me to find which object list to go through and remove the object from as there may be several lists in different placed in the model.
An HTML input only passes "name=value" when a form post occurs so that's all you have to work with. With <input type=submit> you're further limited by the fact that the button's value is its caption (i.e. "myControl=Click Me!" is posted), so you can't stick anything programmatically meaningful in the value.
Method 1: So you're left with encoding all the information you need into the input's name - an approach that works fine, but you'll have to have to go digging into the controller action method's FormCollection parameter rather than relying on model binding. For example:
<input name="delete$#(_scope.Prefix)$#objectGUID" type="submit" value="Delete me" />
Better, have a helper class that encapsulates the string format with a ToString override and has Parse/TryParse/etc static methods, which could be used like this:
<input name="#(new DeleteToken{Prefix=_scope.Prefix, objectGUID=IdentifyingGUID})" type="submit" value="Delete me" />
In your action method:
[HttpPost]
public ActionResult Foo(FormCollection formData)
{
var deleteTokens = DeleteToken.ParseAll(formData.AllKeys);
foreach (var token in deleteTokens)
{
//...do the deletion
}
}
Method 2: An alternative approach is to group each item into its own <form> (bear in mind you can't nest forms) - so when the submit happens, only its surrounding form is posted in which you can stash hidden inputs with the necessary data. e.g.
<ul class="ulMedicationsControl">
<form ... >
<!-- hidden field and submit button and whatever else here -->
...
</form>
</ul>

ASP.NET MVC How to apply role-based or authentication-based View rendering?

i want to show/hide certain parts of a View based on Authentication-status or Roles. For my controller actions I have extended ActionFilterAttribute so I can attribute certain Actions.
<RequiresRole(Role:="Admin")> _
Function Action() as ActionResult
Return View()
End Function
Is there a similar way (attributing) which I can use in the Views? (so not like this: How can I create a view that has different displays according to the role the user is in?)
You can access the user's logged-in roles from the view like this:
<% if (Page.User.IsInRole("Admin")) { %>
<td>
<%= Html.DeleteButton("delete", model.ID) %>
</td>
<% } %>
and maybe your extension method with something like:
public static string DeleteButton(this HtmlHelper html,
string linkText, int id)
{
return html.RouteLink(linkText,
new { ID = id, action = "Delete" },
new { onclick = "$.delete(this.href, deleteCompleted()); return false;" });
}
Obviously, I'm using JavaScript to perform an HTTP DELETE to my controller action, to prevent page crawlers from accidentally deleting data from getting my pages. In my case I'm extending JQuery with a delete() method to supplement the HTTP verb.
I new this existed, but took a while to find. Here's what I am using:
<asp:LoginView runat="server">
<AnonymousTemplate>
You are not logged in yet. Please log in.
</AnonymousTemplate>
<RoleGroups>
<asp:RoleGroup Roles="Admin">
<ContentTemplate>
You are an Admin.
</ContentTemplate>
</asp:RoleGroup>
<asp:RoleGroup Roles="Customers">
<ContentTemplate>
You are a customer.
</ContentTemplate>
</asp:RoleGroup>
</RoleGroups>
<LoggedInTemplate>
Simple Log in check
</LoggedInTemplate>
</asp:LoginView>
This allows you to show different content to different users based on their login state or credentials.

Resources