I am creating finance application in mvc 4 and razor. in that there is one module Journal.
One Journal can have multiple entries. and Journal can not be created without Journal Entry.
Following is my model
using Sms.Core;
using System;
using System.Collections.Generic;
namespace Sms.CoreSociety
{
public class Journal : BaseClass
{
public Journal()
{
this.JournalEntries = new List<JournalEntry>();
}
public virtual string VoucherNo { get; set; }
public virtual DateTime VoucherDate { get; set; }
public string VoucherDateView
{
get
{
return VoucherDate.ToShortDateString();
}
}
public IList<JournalEntry> JournalEntries { get; set; }
public IList<Ledger> Accounts { get; set; }
public double TotalAmount
{
get
{
double sum = 0;
if (JournalEntries != null && JournalEntries.Count > 0)
foreach (var journal in JournalEntries)
sum = journal.Principal + journal.Interest + sum;
return sum;
}
}
}
}
Following is my View
#model Sms.CoreSociety.Journal
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm(null, null, FormMethod.Post, new Dictionary<string, object>() { { "class", "form-horizontal" }, { "id", "document" } }))
{
#Html.ValidationSummary(true)
<fieldset>
<div class="row">
<div class="span1">
<label>
Voucher No</label>
</div>
<div class="span5">
#Html.TextBoxFor(model => model.VoucherNo)
</div>
</div>
<div class="row">
<div class="span1">
<label>
Voucher Date</label>
</div>
<div class="span5">
#Html.TextBoxFor(model => model.VoucherDate)
</div>
</div>
<div class="row">
<div class="span1">
<label>
Amount</label>
</div>
<div class="span5">
#Html.TextBoxFor(model => model.TotalAmount)
</div>
</div>
#Html.TextBox("JournalEntries[0].AccountName", Model.JournalEntries.FirstOrDefault().AccountName)
#Html.TextBox("JournalEntries[0].DebitCredit", Model.JournalEntries.FirstOrDefault().DebitCredit)
#Html.TextBox("JournalEntries[0].Interest", Model.JournalEntries.FirstOrDefault().Interest)
#Html.TextBox("JournalEntries[0].Narration", Model.JournalEntries.FirstOrDefault().Narration)
<input type="submit" value="Save" class="btn" id="submit" />
#if (Model.Id != new Guid())
{
<div style="float: right">
<a class="btn btn-danger" href='#Url.Action("Delete")/#Model.Id' aria-hidden="true">
Delete</a>
</div>
}
</fieldset>
}
<h4>
Journal Entry</h4>
<p>
#Html.ActionLink("Add Entry", "JournalEntry");
Now I am able to get the Journal as well as Single Journal Entry. But my problem is I am not able to make Multiple journal entry.
This is what i am looking for but in MVC 4 and razor without knockout.js
To achieve your goal, you need to do some extra works by jquery, ajax and partial views.
A brief example is here. A full howto is here.
Related
Now I get a JsonString from a column of a dbTable, and then I need to map them into the classes I wrote.
The Problem is that, when I use a for loop to map all the value in razor page, it's totally fine when I use #textBoxFor, but #DropDownListFor no.
this is my razor page code.
#model unitManager.Models.VM_PC_Unit_Mstr
#using unitManager.Models
#{
Layout = "~/Views/Shared/_PageLayout.cshtml";
ViewBag.Title = "Edit";
var controller = ViewContext.RouteData.Values["controller"].ToString();
var action = ViewContext.RouteData.Values["action"].ToString();
bool isCreate = action.EndsWith("Create", StringComparison.OrdinalIgnoreCase);
ViewBag.title = isCreate ? "Create" : "Edit";
}
<style>
.menu_item {
background-color:darkgray;
}
.sub_item{
background-color:azure;
}
</style>
<!-- Basic Inputs Validation start -->
<div class="card">
<div class="card-block">
<form id="main" method="post" #*action="/" novalidate=""*#>
#* Course Name *#
<div class="form-group row">
<label class="col-sm-1 col-form-label">Course Name</label>
<div class="col-sm-3">
#if (!isCreate)
{
#Html.TextBoxFor(n => n.unit_id, new { #class = "form-control", #readonly = "true" })
}
else
{
#Html.TextBoxFor(n => n.unit_id, new { #class = "form-control required", #required = "required" })
}
<span class="messages"></span>
</div>
<div>
#Html.ValidationMessageFor(n => n.unit_id, null, new { #class = "text-danger text-center" })
</div>
</div>
#{
if (Model.menu_obj.menus != null)
{
for (var i = 0; i < Model.menu_obj.menus.Count; i++)
{
var item = Model.menu_obj.menus[i];
string menu_id = "menu-" + i;
<div id="#menu_id" class="menu_item">
#* type *#
<div class="form-group row">
<label class="col-md-3 col-form-label">Type</label>
<div class="col-md-9">
<input id="#(menu_id + "-type")" type="text" value="#item.type">
</div>
</div>
#* No *#
<div class="form-group row">
<label class="col-md-3 col-form-label">No</label>
<div class="col-md-9">
<input id="#(menu_id + "-No")" type="text" value="#item.No">
</div>
</div>
#* tittle *#
<div class="form-group row">
<label class="col-md-3 col-form-label">Title</label>
<div class="col-md-9">
<input id="#(menu_id + "-title")" type="text" value="#item.title">
</div>
</div>
#* url *#
<div class="form-group row">
<label class="col-md-3 col-form-label">Url</label>
<div class="col-md-9">
<input id="#(menu_id + "-url")" type="text" value="#item.url">
</div>
</div>
#* subItem *#
<div class="form-group row">
<label class="col-md-3 col-form-label">SubItem</label>
<div class="col-md-9">
#if (item.content != null)
{
for (var j = 0; j < item.content.Count; j++)
{
var subItem = item.content[j];
string sub_id = "m-" + i + "-sub-" + j;
<div class="sub_item">
#* type *#
<div class="form-group row">
<label class="col-sm-3 col-form-label">Type</label>
<div class="col-sm-9">
#Html.TextBoxFor(p => p.menu_obj.menus[i].content[j].type)
#Html.DropDownListFor(p => p.menu_obj.menus[i].content[j].type, ModelSelectList.subType())
</div>
</div>
#* SubNo *#
<div class="form-group row">
<label class="col-sm-3 col-form-label">Intro</label>
<div class="col-sm-9">
<input id="#(sub_id + "-SubNo")" type="text" value="#subItem.SubNo">
</div>
</div>
#* intro *#
<div class="form-group row">
<label class="col-sm-3 col-form-label">Intro</label>
<div class="col-sm-9">
<input id="#(sub_id + "-intro")" type="text" value="#subItem.intro">
</div>
</div>
#* title *#
<div class="form-group row">
<label class="col-sm-3 col-form-label">Title</label>
<div class="col-sm-9">
<input id="#(sub_id + "-title")" type="text" value="#subItem.title">
</div>
</div>
#* shortcut *#
<div class="form-group row">
<label class="col-sm-3 col-form-label">Shortcut</label>
<div class="col-sm-9">
<input id="#(sub_id + "-shortcut")" type="text" value="#subItem.shortcut">
</div>
</div>
#* url *#
<div class="form-group row">
<label class="col-sm-3 col-form-label">Url</label>
<div class="col-sm-9">
<input id="#(sub_id + "-url")" type="text" value="#subItem.url">
</div>
</div>
#* record_timing *#
<div class="form-group row">
<label class="col-sm-3 col-form-label">Record_timing</label>
<div class="col-sm-9">
<input id="#(sub_id + "-recordtime")" type="text" value="#subItem.record_timing">
</div>
</div>
</div>
}
}
</div>
</div>
</div>
}
}
}
<div class="form-group row">
<div class="col-sm-4" style="display:flex;justify-content:flex-end">
<a type="button" class="btn btn-primary" style="color:white;margin:10px;" href="#Url.Action("Index","UnitMgr")">Cancel</a>
<button type="submit" class="btn btn-primary" style="color:white;margin:10px;">Submit</button>
</div>
</div>
</form>
</div>
</div>
<script>
$("div[id ^='menu-']").each(function () {
console.log($(this));
let menu_idx = $(this).attr("id").replace("menu-", "");
console.log(menu_idx);
$("input[id ^= 'm-" + menu_idx + "-sub-']").each(function () {
console.log("sub", $(this), $(this).val());
});
});
$(function () {
$(".select2").select2();
});//document ready
</script>
this is my controller action looks like
[HttpGet]
public ActionResult Menu(string unit_id)
{
VM_PC_Unit_Mstr model= PC_Unit_Mstr.getMenuByunitID(unit_id);
model.menu_obj = JsonConvert.DeserializeObject<Menu>(model.menus_json);
return View(model);
}
and the ViewModel I use
public class VM_PC_Unit_Mstr
{
public string unit_id { get; set; }
public string menus_json { get; set; }
public VM_Menu.Menu menu_obj { get; set; }
}
The problem I met is in here, which I can map the value with TextBoxFor successfully, but not dropDownListFor.
#Html.TextBoxFor(p => p.menu_obj.menus[i].content[j].type)
#Html.DropDownListFor(p => p.menu_obj.menus[i].content[j].type, ModelSelectList.subType())
And this is the result I get in the web page:
This is the simple function I wrote to get the DropDownList :
public static SelectList subType()
{
List<SelectListItem> itemList = new List<SelectListItem>();
SelectListItem itemSpeaking = new SelectListItem
{
Value = "speaking",
Text = "speaking",
};
SelectListItem itemWords = new SelectListItem
{
Value = "words",
Text = "words",
};
SelectListItem itemGame = new SelectListItem
{
Value = "game",
Text = "game",
};
itemList.Add(itemSpeaking);
itemList.Add(itemWords);
itemList.Add(itemGame);
return new SelectList(itemList, "Value", "Text");
}
This is what VM_Menue is:
public class VM_Menu
{
#region MenuList (MenuListInfo)
public class MenuList
{
public string WelcomeImage { get; set; }
public string Menus { get; set; }
}
public class Menu
{
public string welcomeImg { get; set; }
public List<MenuData> menus { get; set; }
}
public class MenuData
{
public string type { get; set; } //video or game or conclusion
public string No { get; set; }
public string title { get; set; }
public string url { get; set; }
public List<SubItemData> content { get; set; }
}
public class SubItemData
{
public string type { get; set; } //speaking or words or game
public string SubNo { get; set; }
public string intro { get; set; }
public string title { get; set; }
public string shortcut { get; set; }
public string url { get; set; }
public float? record_timing { get; set; }
}
#endregion
}
At first, my purpose is to make a two level input/dropDownList tree,
which allows user to edit dynamically, how many parent node user wants,
below the current parent node, how many sub node user wants to edit, create or delete.
So, before this function I want to make, I firstly encounter this dropdownlist mapping problem
with #html function.
Hope the intention and information I offer is enough and clear.
Thank you all for reviewing my codes, it is a mess I know.
I'm afraid you cannot set selected option with #Html.DropDownListFor.You can try to foreach ModelSelectList.subType() and add selected to the option if the value is the same with menu_obj.menus[i].content[j].type:
<select name="menu_obj.menus[#i].content[#j].type">
#foreach (var item in ModelSelectList.subType())
{
if (item.Text == Model.menu_obj.menus[i].content[j].type)
{
<option value=#item.Value selected>#item.Text</option>
}
else
{
<option value=#item.Value>#item.Text</option>
}
}
</select>
ModelSelectList.subType()
#foreach (var item in ModelSelectList.subType()) {
//
}
I'm trying to create a form in asp.net core 3 MVC.
the model is a "package" class that contains different properties about the package, and a List<item> items property of the items in the package , item is a class defined that contains different properties of an "item".
how should I approach creating a form for the user to add a new "package" ?
plus inserting the items inside it, which could be any amount of items , I would like the user to insert a row for each item (with a button that adds new input row for a new item ) and submit it with the final form .
any help would be appreciated.
Here is a whole working demo:
Model:
public class Package
{
public int Id { get; set; }
public string Name { get; set; }
public List<Item> Items { get; set; }
}
public class Item
{
public int Id { get; set; }
public string ItemName { get; set; }
}
View:
#model Package
<h1>Create</h1>
<h4>Package</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<button onclick="addRow()" type="button">Add Row</button>
<table id="AddItemsTable">
<tr>
<th>#Html.DisplayNameFor(model=>model.Items[0].ItemName)</th>
</tr>
</table>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
JS:
#section Scripts {
<script>
var counter = 0;
function addRow() {
var table = document.getElementById("AddItemsTable");
var row = table.insertRow(-1);
var cell1 = row.insertCell(0);
cell1.innerHTML = '<input type="text" name="Items[' + counter+'].ItemName"/>';
counter++;
}
</script>
}
Controller:
// GET: Packages/Create
public IActionResult Create()
{
return View();
}
// POST: Packages/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Package package)
{
if (ModelState.IsValid)
{
_context.Add(package);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(package);
}
Result:
First of all forgive me as I am new to MVC.
I have a view which shows server(s) related to a particular application. If none exist, or the user wants to add an additional application/server relationship, they click on "Create New". From this link, I would like the ApplicationID to be passed to the Create view, and the selectlist for Applications to default to the correct Application. Or alternatively, display the application name/id in a label. I would also like to pass the ApplicationId back when "Back to List" is selected.
Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace ApplicationPortfolio.Models
{
[Table("tblServerApp")]
public class ServerApp
{
public int ServerAppId { get; set; }
public int? ApplicationId { get; set; }
public int? ServerId { get; set; }
public virtual Application Application { get; set; }
public virtual Server Server { get; set; }
}
}
Controller:
// GET: ServerApps/Create
public IActionResult Create(int? id)
{
ViewData["ApplicationId"] = new SelectList(_context.Application, "ApplicationID", "Name", id);
ViewData["ServerId"] = new SelectList(_context.Server, "ServerId", "ServerName");
return View();
}
View:
#model ApplicationPortfolio.Models.ServerApp
#{
ViewData["Title"] = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Create</h1>
<h4>ServerApp</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="form-group">
<label asp-for="ApplicationId" class="control-label"></label>
<select asp-for="ApplicationId" class="form-control" asp-items="ViewBag.ApplicationId"></select>
</div>
</div>
<div class="form-group">
<label asp-for="ServerId" class="control-label"></label>
<select asp-for="ServerId" class ="form-control" asp-items="ViewBag.ServerId"></select>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
After my test,I found your problem may in your code:
ViewData["ApplicationId"] = new SelectList(_context.Application, "ApplicationID", "Name", id);
ApplicationID and Name should be same with the name in your Application model.
If your model is(example) :
public class Application
{
[Key]
public int ApplicationId { get; set; }
public string ApplicationName { get; set; }
public List<ServerApp> ServerApps { get; set; }
}
Your code should be(Please pay attention to whether the case and match) :
ViewData["ApplicationId"] = new SelectList(_context.Applications, "ApplicationId", "ApplicationName",id);
And if you want to pass the ApplicationId back to Index,you can try following code.
#model ServerApp
#{
ViewData["Title"] = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h4>ServerApp</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="form-group">
<label asp-for="ApplicationId" class="control-label"></label>
<select id="select" asp-for="ApplicationId" class="form-control" asp-items="ViewBag.ApplicationId"></select>
</div>
</div>
<div class="form-group">
<label asp-for="ServerId" class="control-label"></label>
<select asp-for="ServerId" class="form-control" asp-items="ViewBag.ServerId"></select>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<button id="submit" class="btn btn-info">Back to List</button>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script>
$("#submit").click(function (e) {
e.preventDefault();
var e = document.getElementById("select");
var strUser = e.value;
window.location.href = "/home/index?id=" + strUser;
})
</script>
}
Test Result:
I'm trying to develop an ASP.NET MVC application using C# and EF with a code-first approach.
I have two classes Actors and Movies which have many-to-many relationships (an Actor can be in many Movies, a Movie can have many Actors).
Everything is working properly, but I can not access the intermediate (MoviesActors) table through a view (this table is generated automatically as a result of the many-to-many relationship between Actors and Movies). I want to access this table so that I could assign the correct primary keys to determine things like "How many movies does a particular actor have?" and "How many actors have played a role in a particular movie?".
These are my models:
public class Actors
{
public Actors()
{
this.mvz = new HashSet<Movies>();
}
public int Id { get; set; }
public string actor_name { get; set; }
public string country { get; set; }
public virtual ICollection<Movies> mvz { get; set; }
}
public class Movies
{
public Movies()
{
this.actz = new HashSet<Actors>();
}
public int Id { get; set; }
public string Movie_title { get; set; }
public string genre { get; set; }
public virtual ICollection<Actors> actz { get; set; }
}
I have two models as above and three tables in database.
Now from a view, I can access the actors model and the movies model but when it comes to the intermediate table (MoviesActors), I can not access its model because it does not exist, which means I can not reference MoviesActors in a view and can't enter data through a form.
I would like to ask if my approach is correct or not, I mean in a real world application do we have to access the composite key table and do the data entry, or is there any better approach to solve this issue?
By the way this is the controller:
public ActionResult DataEntry()
{
return View();
}
[HttpPost]
public ActionResult Add(??? mva)
{
_context.act.Add(mva.act);
_context.mvz.Add(mva.mvz);
_context.SaveChanges();
return RedirectToAction("Index","Actors");
}
And this is the view:
#model Many_To_Many_Relationship_Latest.?.?
#{
ViewBag.Title = "DataEntry";
Layout = "~/Views/Shared/_Layout.cshtml";
}
At the top, I should be able to access the MoviesActors table via Model or ViewModel (Check the two places with question marks) but I'm not able to do so.
If anyone having expertise in this regard is reading this post, kindly guide me with the correct logic or any other approach that helps me get the result.
Many thanks in advance.
This is my new razor view
#model Many_To_Many_Relationship_Latest.ViewModel.MoviesActorsViewModel
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
#{
ViewBag.Title = "DataEntry";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h5>Enter Data in Movies_Actors Table</h5>
#using (Html.BeginForm("Add","MoviesActors"))
{
<div class="form-group">
#Html.LabelFor(a=> a.mvz.Movie_title)
#Html.TextBoxFor(a=> a.mvz.Movie_title, new { #class="form-control"})
</div>
<div class="form-group">
#Html.LabelFor(a => a.mvz.genre)
#Html.TextBoxFor(a => a.mvz.genre, new { #class = "form-control" })
</div>
foreach (var item in Model.act)
{
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox control-group">
<label>
<!-- SEE id property here, I've made it dynamic -->
<input type="checkbox" id="cb_#item.Id" value="#item.Id" class="checkBoxClass" />
<label>#item.actor_name</label>
</label>
</div>
</div>
</div>
}
<div>
<input type="hidden" name="Ids" id="Ids" />
</div>
<button type="submit" class="btn btn-primary">Save</button>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<script>
$(function () {
var ids = [];
$(".checkBoxClass").change(function () {
if (this.checked) {
ids.push(this.value);
}
else {
var index = ids.indexOf(this.value);
ids.splice(index, 1);
}
$('#ids').val(ids);
});
});
</script>
The intermediate table is hidden by Entity framework but don't worry mvc have fabulous feature that is ViewModel to do your job that means you can to create view for intermediate table like MoviesActors
So for,
1) You have to create one view model for your intermediate table like
public class MoviesActorsViewModel
{
public MoviesActorsViewModel()
{
mvz = new Movies();
act = new Actors();
}
public Movies mvz { get; set; }
public Actors act { get; set; }
}
2) Add view for above view model like
public ActionResult GetView()
{
MoviesActorsViewModel mcvm = new MoviesActorsViewModel();
return View(mcvm);
}
3) Then your view for above action method like.
The below razor is for your understanding purpose only. your actual razor may differ from this.
#model WebApplication2.Controllers.MoviesActorsViewModel
#{
ViewBag.Title = "GetView";
}
<h2>GetView</h2>
#using (Html.BeginForm("Create", "Default", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>MoviesActorsViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
//mvz fields below
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.mvz.movie_title, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.mvz.genre, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
//act fields below
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.act.actor_name, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.act.country_of_birth, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
4) After you submit your form then your post method will add your mvz and act like
[HttpPost]
public ActionResult Create(MoviesActorsViewModel mcvm)
{
_context.mvz.Add(mcvm.mvz);
_context.actrs.Add(mcvm.act);
return RedirectToAction("GetView", "Default");
}
Note: The above code snippet is for one movie and one actor.
So if you want to add multiple actors to single movie then change your act property in MoviesActorsViewModel to List
Like public List<Actors> act { get; set; } and add multiple textbox in view and after posting your form to action method Create add those multiple actors like _context.actrs.AddRange(mcvm.act);
Edit:
I have to register a new actor too. But I want to select actors from the actors table and assign them to the new movies that gets registered.
If you have to assign multiple actors to movie while adding new movie then
1) You view model is
public class MoviesActorsViewModel
{
public MoviesActorsViewModel()
{
mvz = new Movies();
act = new List<Actors>();
}
public Movies mvz { get; set; }
public List<Actors> act { get; set; }
public string[] ids { get; set; }
}
2) Populate your actors from db to view model's act list from your get view action method
public ActionResult GetView()
{
MoviesActorsViewModel mcvm = new MoviesActorsViewModel();
mcvm.act = _context.actrs.ToList();
return View(mcvm);
}
3) In razor view you have to enter one movie and choose multiple actors for it then simply take checkbox for each of actors and add its respective id values to array and then pass this array with form submit.
#model WebApplicationMVC1.Controllers.MoviesActorsViewModel
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
#{
ViewBag.Title = "GetView";
}
<h2>GetView</h2>
#using (Html.BeginForm("Create", "Default1", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>MoviesActorsViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
//mvz fields below
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.mvz.movie_title, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.mvz.genre, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
//act fields below from list of actors
#foreach (var item in Model.act)
{
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox control-group">
<label>
<!-- SEE id property here, I've made it dynamic -->
<input type="checkbox" id="cb_#item.Id" value="#item.Id" class="checkBoxClass" />
<label>#item.actor_name</label>
</label>
</div>
</div>
</div>
}
<div>
<input type="hidden" name="ids" id="ids" />
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<script>
$(function () {
var ids = [];
$(".checkBoxClass").change(function () {
if (this.checked) {
ids.push(this.value);
}
else {
var index = ids.indexOf(this.value);
ids.splice(index, 1);
}
$('#ids').val(ids);
});
});
</script>
4) After submit your form to below action you can loop through each of id of actor and save it to database with movie
[HttpPost]
public ActionResult Create(MoviesActorsViewModel mcvm)
{
_context.mvz.Add(mcvm.mvz);
foreach (var id in mcvm.ids)
{
int id1 = Convert.ToInt32(id);
Actors act = _context.actrs.Find(x => x.Id == id1);
_context.actrs.Add(act);
}
return RedirectToAction("GetView", "Default");
}
#Prince_Walizada as you said, you have a third table which is called a Junction Table and by using EF there is no need to access to this table. because you can directly add any number of the other entity to the current record.
For example (this is pseudo code):
var Movie = MyContext.Movies.Where(P=>Title.Contains("Star war")).FirstOrDefault();
Movie.Actors.Add(new Actor() { Name = "Mike" , ...}
Movie.Actors.Add(new Actor() { Name = "Joe" , ...}
Movie.Actors.Add(new Actor() { Name = "Daniel" , ...}
and you could do this also in reverse:
var Actor = MyContext.Movies.Where(P=>Name.Contains("Mike")).FirstOrDefault();
Actor.Movies.Add(new Movie() { Title = "World of War" , ...}
Actor.Movies.Add(new Movie() { Title = "hobbits" , ...}
Actor.Movies.Add(new Movie() { Title = "toy story" , ...}
As you see, you don't need to know about that third table.
I have merged two views in one view(one to create and the other one to display).So the new view will be able to add and retrieve data in the same time.
but it was only able to create a new row in the database without retrieve anything. There is 4 rows in the database.
here is my new view (Index): i added h1> Works/h1> to make sure foreach works
Index.cshtml
#model ReMvc.ViewModel.MovieViewModel
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Movie</legend>
<div class="editor-label">
#Html.LabelFor(movie => movie.Movie.Title)
</div>
<div class="editor-field">
#Html.EditorFor(movie => movie.Movie.Title)
#Html.ValidationMessageFor(movie => movie.Movie.Title)
</div>
<div class="editor-label">
#Html.LabelFor(movie => movie.Movie.ReleaseDate)
</div>
<div class="editor-field">
#Html.EditorFor(movie => movie.Movie.ReleaseDate)
#Html.ValidationMessageFor(movie => movie.Movie.ReleaseDate)
</div>
<div class="editor-label">
#Html.LabelFor(movie => movie.Movie.Genre)
</div>
<div class="editor-field">
#Html.EditorFor(movie => movie.Movie.Genre)
#Html.ValidationMessageFor(movie => movie.Movie.Genre)
</div>
<div class="editor-label">
#Html.LabelFor(movie => movie.Movie.Price)
</div>
<div class="editor-field">
#Html.EditorFor(movie => movie.Movie.Price)
#Html.ValidationMessageFor(movie => movie.Movie.Price)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
foreach (var item in Model.MovieCollection)
{
<tr>
<h1>Works</h1>
<td>
#Html.Display(item.Title)
</td>
<td>
#Html.Display(item.ReleaseDate.ToString())
</td>
<td>
#Html.Display(item.Genre)
</td>
<td>
#Html.Display(item.Price.ToString())
</td>
</tr>
}
}
<p>
</p>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
My problem that from the above code foreach doesn't retrieve data from MovieCollection to index page.
Here is my model (Movie):
using System;
using System.Data.Entity;
namespace ReMvc.Models
{
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public decimal Price { get; set; }
}
public class MovieDbContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
}
And here is a new type to solve an issue:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ReMvc.ViewModel
{
public class MovieViewModel
{
public ReMvc.Models.Movie Movie { get; set; }
public IEnumerable<ReMvc.Models.Movie> MovieCollection { get; set; }
}
}
Here is my controller:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ReMvc.Models;
using ReMvc.ViewModel;
namespace ReMvc.Controllers
{
public class MoviesController : Controller
{
private MovieDbContext db = new MovieDbContext();
//
// GET: /Movies/
public ActionResult Index()
{
var model = new MovieViewModel()
{ MovieCollection = db.Movies.ToList(), };
return View(model);
}
//
// POST: /Movies/Index
[HttpPost]
public ActionResult Index(Movie movie)
{
if (ModelState.IsValid)
{
db.Movies.Add(movie);
db.SaveChanges();
return RedirectToAction("Index");
}
var model = new MovieViewModel()
{
Movie = movie,
};
return View(movie);
}
}
In your post action, you're not setting a value for MovieCollection on your view model. This information doesn't survive the request, and you're not even accepting the full view model from the post, if it did. As a result, you simply need to repopulate the list in your post action before returning the view.
1. add the Enumerable list of row to use it with foreach, in the model in the entity folder:
public partial class UserProfile
{
public int UserId { get; set; }
public string UserName { get; set; }
public string PostContent { get; set; }
public IEnumerable<workingOnAddPost.Entity.UserProfile> UserProfilesCollection { get; set; }
2. edit the home controller, to make it deal with httpPost and httpGet requests
public class HomeController : Controller
{
private AddingPostEntities db = new AddingPostEntities();
[HttpGet]
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
//return View( db.UserProfiles.ToList());
var model = new UserProfile()
{
UserProfilesCollection = db.UserProfiles.ToList(),
};
return View(model);
}
[HttpPost]
public ActionResult Index(UserProfile userprofile)
{
if (ModelState.IsValid)
{
db.UserProfiles.Add(userprofile);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(userprofile);
}
//
// POST: /PostManager/Create
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
// GET: /PostManager/Details/5
public ActionResult Details(int id = 0)
{
UserProfile userprofile = db.UserProfiles.Find(id);
if (userprofile == null)
{
return HttpNotFound();
}
return View(userprofile);
}
//
// GET: /PostManager/Edit/5
public ActionResult Edit(int id = 0)
{
UserProfile userprofile = db.UserProfiles.Find(id);
if (userprofile == null)
{
return HttpNotFound();
}
return View(userprofile);
}
//
// POST: /PostManager/Edit/5
[HttpPost]
public ActionResult Edit(UserProfile userprofile)
{
if (ModelState.IsValid)
{
db.Entry(userprofile).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(userprofile);
}
//
// GET: /PostManager/Delete/5
public ActionResult Delete(int id = 0)
{
UserProfile userprofile = db.UserProfiles.Find(id);
if (userprofile == null)
{
return HttpNotFound();
}
return View(userprofile);
}
//
// POST: /PostManager/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
UserProfile userprofile = db.UserProfiles.Find(id);
db.UserProfiles.Remove(userprofile);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
3.edit the index page to contain the two views, one for adding and the second to retrieve , as below:
#using System.Linq;
#model workingOnAddPost.Entity.UserProfile
#{
};
#*<p>*#
<script src="~/Scripts/jquery-2.1.1.min.js"></script>
<script src="~/Scripts/masonry.pkgd.min.js"></script>
<script src="~/Scripts/myScript.js"></script>
<link href="~/Content/Styles/font-awesome.css" rel="stylesheet" />
<link href="~/Content/Styles/main.css" rel="stylesheet" />
#*<div class="Button addcontent">
<button type="button" >
<em class="icon-plus"></em>
</button>
</div>*#
##
#section featured {
<section class="featured">
<div class="content-wrapper">
<hgroup class="title">
<h1>#*ViewBag.Title.*#</h1>
<h2>#*ViewBag.Message*#</h2>
</hgroup>
<p>
To learn more about ASP.NET MVC visit
http://asp.net/mvc.
The page features <mark>videos, tutorials, and samples</mark> to help you get the most from ASP.NET MVC.
If you have any questions about ASP.NET MVC visit
our forums.
</p>
</div>
</section>
}
<div class="Button addcontent">
<button type="button">
<em class="icon-plus"></em>
</button>
</div>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="modal-addcontent">
<div class="modal">
<div class="standardForm">
<h1>
Add new content
</h1>
<ul>
<li>
<h3>
<label>
Id=
</label>
</h3>
<div class="editor-field">
#Html.EditorFor(model => model.UserId)
#Html.ValidationMessageFor(model => model.UserId)
</div>
</li>
<li>
<h3>
<label>
Name:
</label>
</h3>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
</li>
<li>
<h3>
<label>
Description
</label>
</h3>
<div class="content">
#Html.TextAreaFor(model => model.PostContent)
#Html.ValidationMessageFor(model => model.PostContent)
</div>
</li>
<li>
<h3>
<label>
Image
</label>
</h3>
<div>
<input id="upload" type="file" />
</div>
</li>
</ul>
<div class="formFooter">
<div class="FooterButtons">
<button class="Button btn close-modalpopup" type="button">
<span class="buttonText">
Cancel
</span>
</button>
<p>
<button class="Button primary btn" type="submit" value="Create">
<span class="buttonText">
Create
</span>
</button>
</p>
</div>
</div>
</div>
</div>
</div>
}
<h3>We suggest the following:</h3>
<ol class="round">
<li class="one">
<h5>Getting Started</h5>
ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that
enables a clean separation of concerns and that gives you full control over markup
for enjoyable, agile development. ASP.NET MVC includes many features that enable
fast, TDD-friendly development for creating sophisticated applications that use
the latest web standards.
Learn more…
</li>
<li class="two">
<h5>Add NuGet packages and jump-start your coding</h5>
NuGet makes it easy to install and update free libraries and tools.
Learn more…
</li>
<li class="three">
<h5>Find Web Hosting</h5>
You can easily find a web hosting company that offers the right mix of features
and price for your applications.
Learn more…
</li>
</ol>
#*<table>*#
#foreach (var item in Model.UserProfilesCollection)
{
<div id="main">
<div id="main-inner">
<div id="container" class="js-masonry" data-masonry-options='{ "columnWidth": ".grid-sizer", "itemSelector": ".item"}'>
<div class="grid-sizer">
<div class="item open-modal">
<p>
#Html.DisplayTextFor(Modelitem => item.PostContent)
</p>
</div>
</div>
</div>
</div>
</div>
}
#* </table>*#