Skip to content

Instantly share code, notes, and snippets.

@rockfordlhotka
Last active June 27, 2018 21:47
Show Gist options
  • Save rockfordlhotka/a8b3253a8ee3b318ce6d30f733529075 to your computer and use it in GitHub Desktop.
Save rockfordlhotka/a8b3253a8ee3b318ce6d30f733529075 to your computer and use it in GitHub Desktop.
In-place edit of list in Razor Pages w/ CSLA
@page
@model WebApplication3.Pages.MyList.CreateModel
@{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>MyItem</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="MyItem.Name" class="control-label"></label>
<input asp-for="MyItem.Name" class="form-control" />
<span asp-validation-for="MyItem.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MyItem.City" class="control-label"></label>
<input asp-for="MyItem.City" class="form-control" />
<span asp-validation-for="MyItem.City" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace WebApplication3.Pages.MyList
{
public class CreateModel : PageModel
{
public async Task<IActionResult> OnGet()
{
MyItem = await Csla.DataPortal.CreateAsync<MyItem>();
return Page();
}
[BindProperty]
public MyItem MyItem { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
MyItem = await MyItem.SaveAsync();
return RedirectToPage("./Index");
}
}
}
@page
@model WebApplication3.Pages.MyList.IndexModel
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-page="Create">Create New</a>
</p>
<div class="row">
<div class="col-md-4">
<form method="post">
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.DataList[0].Name)
</th>
<th>
@Html.DisplayNameFor(model => model.DataList[0].City)
</th>
</tr>
</thead>
<tbody id="childtable">
@for (int i = 0; i < Model.DataList.Count; i++)
{
<tr>
<td>
<input type="hidden" asp-for="DataList[i].Id" />
<input asp-for="DataList[i].Name" class="form-control" />
<span asp-validation-for="DataList[i].Name" class="text-danger"></span>
</td>
<td>
<input asp-for="DataList[i].City" class="form-control" />
<span asp-validation-for="DataList[i].City" class="text-danger"></span>
</td>
<td>
<input asp-for="DataList[i].Remove" type="checkbox" />
<label class="control-label">Select</label>
</td>
</tr>
}
</tbody>
</table>
<div class="form-group">
<input name="command" type="submit" value="Submit" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace WebApplication3.Pages.MyList
{
public class IndexModel : PageModel
{
[BindProperty]
public MyList DataList { get; set; }
public async Task OnGetAsync()
{
DataList = await Csla.DataPortal.FetchAsync<MyList>();
}
public async Task<IActionResult> OnPostAsync()
{
foreach (var item in DataList.Where(r => r.Remove).ToList())
DataList.Remove(item);
DataList = await DataList.SaveAsync();
return RedirectToPage("Index");
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Csla;
namespace WebApplication3.Pages.MyList
{
[Serializable]
public class MyItem : BusinessBase<MyItem>
{
public static readonly PropertyInfo<int> IdProperty = RegisterProperty<int>(c => c.Id);
public int Id
{
get { return GetProperty(IdProperty); }
private set { LoadProperty(IdProperty, value); }
}
public static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name);
[Required]
public string Name
{
get { return GetProperty(NameProperty); }
set { SetProperty(NameProperty, value); }
}
public static readonly PropertyInfo<string> CityProperty = RegisterProperty<string>(c => c.City);
[Required]
public string City
{
get { return GetProperty(CityProperty); }
set { SetProperty(CityProperty, value); }
}
public static readonly PropertyInfo<bool> RemoveProperty = RegisterProperty<bool>(c => c.Remove);
public bool Remove
{
get { return GetProperty(RemoveProperty); }
set { SetProperty(RemoveProperty, value); }
}
private void Child_Fetch(MockDb.DbItem data)
{
using (BypassPropertyChecks)
{
Id = data.Id;
Name = data.Name;
City = data.City;
}
}
[RunLocal]
protected override void DataPortal_Create()
{
base.DataPortal_Create();
}
protected override void DataPortal_Insert()
{
Child_Insert();
}
private void Child_Insert()
{
using (BypassPropertyChecks)
{
Id = MockDb.Items.Max(r => r.Id) + 1;
MockDb.Items.Add(new MockDb.DbItem { Id = Id, Name = Name, City = City });
}
}
private void Child_Update()
{
using (BypassPropertyChecks)
{
var existing = MockDb.Items.Where(i => i.Id == Id).FirstOrDefault();
if (existing == null)
throw new InvalidOperationException("No existing item in database {Id}");
existing.Id = Id;
existing.Name = Name;
existing.City = City;
}
}
private void Child_DeleteSelf()
{
var existing = MockDb.Items.Where(i => i.Id == Id).FirstOrDefault();
if (existing == null)
throw new InvalidOperationException("No existing item in database {Id}");
MockDb.Items.Remove(existing);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Csla;
namespace WebApplication3.Pages.MyList
{
public static class MockDb
{
public static List<DbItem> Items = new List<DbItem>
{
new DbItem { Id = 1, Name = "Rocky", City = "Aitkin"},
new DbItem { Id = 3, Name = "Teresa", City = "Bemidji"},
new DbItem { Id = 2, Name = "Tim", City = "St. Paul"}
};
public class DbItem
{
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
}
[Serializable]
public class MyList : BusinessListBase<MyList, MyItem>
{
private void DataPortal_Fetch()
{
AddRange(MockDb.Items.Select(i => DataPortal.FetchChild<MyItem>(i)));
}
protected override void DataPortal_Update()
{
Child_Update();
}
}
}
// in startup.cs the ConfigureServices method needs to use CslaModelBinderProvider
services.AddMvc(config =>
config.ModelBinderProviders.Insert(0, new Csla.Web.Mvc.CslaModelBinderProvider(CreateInstanceAsync, CreateChild))
).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// somewhere we also need to provide the CreateInstanceAsync and CreateChild implementations
// one location is in startup.cs
/// <summary>
/// Create an instance of a root object when requested
/// by CslaModelBinder
/// </summary>
/// <param name="type">Type of root object to create</param>
private async Task<object> CreateInstanceAsync(Type type)
{
object result;
if (type.Equals(typeof(Pages.MyList.MyList)))
result = await Csla.DataPortal.FetchAsync<Pages.MyList.MyList>();
else
result = Csla.Reflection.MethodCaller.CreateInstance(type);
return result;
}
/// <summary>
/// Create an instance of a child object when requested
/// by CslaModelBinder
/// </summary>
/// <param name="parent">Reference to parent object</param>
/// <param name="type">Type of child object to create</param>
/// <param name="values">Values that CslaModelBinder will load into the new child object</param>
/// <returns></returns>
private object CreateChild(System.Collections.IList parent, Type type, Dictionary<string, string> values)
{
object result = null;
if (type.Equals(typeof(Pages.MyList.MyItem)))
{
var list = (Pages.MyList.MyList)parent;
var idText = values["Id"];
int id = string.IsNullOrWhiteSpace(idText) ? -1 : int.Parse(values["Id"]);
result = list.Where(r => r.Id == id).FirstOrDefault();
if (result == null)
result = Csla.Reflection.MethodCaller.CreateInstance(type);
}
else
{
result = Csla.Reflection.MethodCaller.CreateInstance(type);
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment