使用 @Html.EditorForModel() 构建表单时如何自动填充特定字段?

发布于 2025-01-05 07:49:32 字数 1994 浏览 1 评论 0原文

我让用户使用 IDE 附带的 AspNetSqlProfileProvider 在我的网站上的某个位置填写他们的个人资料信息。

我允许我的用户随时编辑他们的个人资料,方法是转到编辑个人资料页面,其中会自动填充编辑个人资料的表单。我目前通过使用 ViewBag 将用户配置文件的每个单独部分从我的控制器发送到视图(例如地址和城市)来实现此目的:

Controller get:

ViewBag.address = CustomProfile.GetUserProfile(User.Identity.Name).Address;
ViewBag.city = CustomProfile.GetUserProfile(User.Identity.Name).City;

View:

    <div class="editor-field">
        @Html.TextBox("Address", (string)ViewBag.address)
    </div>

    <div class="editor-field">
        @Html.TextBox("City", (string)ViewBag.city)
    </div>

Controller post:

    public ActionResult ChangeProfile( FormCollection favorites )
    {
        CustomProfile profile = CustomProfile.GetUserProfile();
        profile.Address = favorites["Address"];
        profile.City = favorites["City"];
        profile.Save();
        return RedirectToAction("Profile");
    }

上面的内容对于编辑配置文件效果很好,非常流畅从我的用户的角度来看(尽管,从在线阅读问题/答案来看,我似乎应该使用 ViewModel,但不确定如何进行转换 - 一直失败)。

当我的用户从网站上“结帐”(他们已经购物)时,他们会看到一个屏幕,允许他们输入最终信息以进行购买。我们称之为“订单页面”。这些详细信息包括姓名、地址、信用卡信息等。其中一些信息与网站个人资料页面中的信息相同。

我希望能够自动填充此订单页面中的一些详细信息(姓名、地址),同时将某些字段留空(信用卡 - 因此用户每次访问订单页面时都必须填写这些详细信息) 。

订单页面的工作方式是 MVC 商店教程介绍。当显示订单页面时,它会使用以下方式显示表单:

@Html.EditorForModel()

这很棒,允许您编辑订单模型中指定的详细信息,并允许数据验证内容(名称是必需的,地址是必需的,信用卡必须是数字) 、电子邮件格式正确等),但我无法弄清楚如何使用用户个人资料中的详细信息填充此订单页面中的特定字段。

我尝试构建一个新的 ViewModel,它仅使用我的个人资料中包含的信息,但我不清楚需要什么,因为我没有得到我想要的最终结果。

我考虑过仅使用订单模型作为我的个人资料信息,但这还不够,因为我希望在两者中都提供不同的信息。

我考虑过使用个人资料信息作为订单模型,但我希望我的用户能够灵活地将个人资料信息与他们实际下订单时使用的任何信息分开存储。

我认为要解决我的问题,我需要具体了解的是如何在使用“@Html.EditorForModel()”时自动填充特定字段?

对我的整体情况有任何其他帮助都会很棒,我非常愿意接受任何可以简化我的流程的建议(感觉就像我让自己变得比我需要的更加困难,而且我正处于合作感觉就像呼吸新鲜空气的阶段)。

I have users fill out their profile information somewhere on my site using the AspNetSqlProfileProvider that came with the IDE.

I allow my users to edit their profile at any time by going to the edit profile page where the form to edit their profile auto-populates. I currently do this by using ViewBag to send each individual part of a user's profile from my controller to the view (address and city for example):

Controller get:

ViewBag.address = CustomProfile.GetUserProfile(User.Identity.Name).Address;
ViewBag.city = CustomProfile.GetUserProfile(User.Identity.Name).City;

View:

    <div class="editor-field">
        @Html.TextBox("Address", (string)ViewBag.address)
    </div>

    <div class="editor-field">
        @Html.TextBox("City", (string)ViewBag.city)
    </div>

Controller post:

    public ActionResult ChangeProfile( FormCollection favorites )
    {
        CustomProfile profile = CustomProfile.GetUserProfile();
        profile.Address = favorites["Address"];
        profile.City = favorites["City"];
        profile.Save();
        return RedirectToAction("Profile");
    }

The above works fine for editing profiles, it is very smooth from my user's perspective (although, from reading questions/answers online it appears I should be using a ViewModel, not exactly sure how to make the transition - have been failing).

When my user's go to 'checkout' from the website (they've been shopping), they are presented with a screen that allows them to input final information that allows them to make their purchase. Let's call this the, "Order Page." These details include name, address, credit card info, etc. Some of these pieces of information are the same as the information within the profile page of the website.

I want to be able to auto-populate some of the details in this Order Page (name, address) while leaving some of the fields blank (credit card - so the user has to fill these details in each time they visit the order page).

The way the Order page works is as the MVC Store Tutorial describes. When the Order Page is displayed it displays the form using:

@Html.EditorForModel()

Which is great and allows you to edit the details specified within the Order model and will allow for the data verification stuff (name is required, address is required, credit card has to be numbers, email is properly formatted, etc), but I cannot figure out how to populate specific fields within this Order Page with details from my user's profile.

I have attempted building a new ViewModel that uses just the information contained within my profile, but I do not have a clear grasp of what is needed because I am not getting the end-result I am desiring.

I have considered using just the Order Model as my Profile information, but that is not sufficient because I want to have different information available in both.

I have considered using the Profile information as the Order Model, but I want my users to have the flexibility to store profile information separately from whatever information they use to actually place orders.

I think what I need to know specifically to fix my problem is how do I auto-populate specific fields while using "@Html.EditorForModel()" ?

Any other help with my overall situation would be great, I am very open to any advice that would simplify my flow (it feels like I am making it harder on myself than I need to, and I am at a point where collaboration would feel like a breath of fresh air).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

祁梦 2025-01-12 07:49:32

我只能听懂你问题的前半部分。您在其中展示了一些代码,我可以在其中为您提供帮助。下半场对我来说完全是一片迷雾。

因此,当您想要设计视图时,请考虑该视图需要显示/编辑哪些字段。并为其设计一个视图模型:

public class ChangeProfileViewModel
{
    [Required]
    public string Address { get; set; }

    [Required]
    public string City { get; set; }
}

然后让应该渲染此视图的 GET 控制器操作填充视图模型:

public ActionResult ChangeProfile()
{
    CustomProfile profile = CustomProfile.GetUserProfile(User.Identity.Name);
    ChangeProfileViewModel model = new ChangeProfileViewModel
    {
        Address = profile.Address,
        City = profile.City
    };
    return View(model);
}

然后设计相应的视图,该视图将强类型化到此视图模型:

@model ChangeProfileViewModel
@using (Html.BeginForm())
{
    @Html.EditorForModel()
    <button type="submit">OK</button>
}

最后你有一个 POST 控制器将处理此表单提交的操作:

[HttpPost]
public ActionResult ChangeProfile(ChangeProfileViewModel model)
{
    if (!Model.IsValid)
    {
        // there were validation errors => redisplay the view
        return View(model);
    }

    // validation succeeded => process the results
    CustomProfile profile = CustomProfile.GetUserProfile();
    profile.Address = model.Address;
    profile.City = model.City;
    profile.Save();
    return RedirectToAction("Profile");
}

现在我们在这里观察到,在 GET 和 POST 操作中,我们的域模型 (CustomProfile) 和视图模型之间都有重复的映射代码(ChangeProfileViewModel)。为了解决这个问题,我可能建议您使用AutoMapper。它可以将您的 GET 操作简化为:

public ActionResult ChangeProfile()
{
    CustomProfile profile = CustomProfile.GetUserProfile(User.Identity.Name);
    ChangeProfileViewModel model = Mapper.Map<CustomProfile, ChangeProfileViewModel>(profile);
    return View(model);
}

或使用自定义操作过滤器简化为:

[AutoMap(typeof(CustomProfile), typeof(ChangeProfileViewModel))]
public ActionResult ChangeProfile()
{
    CustomProfile profile = CustomProfile.GetUserProfile(User.Identity.Name);
    return View(profile);
}

以及将您的 POST 操作简化为:

[HttpPost]
public ActionResult ChangeProfile(ChangeProfileViewModel model)
{
    if (!Model.IsValid)
    {
        // there were validation errors => redisplay the view
        return View(model);
    }

    // validation succeeded => process the results
    CustomProfile profile = CustomProfile.GetUserProfile();
    Mapper.Map<ChangeProfileViewModel, CustomProfile>(model, profile);
    profile.Save();
    return RedirectToAction("Profile");
}

关于视图模型,重要的是您应该始终为每个视图使用它们,并以这样的方式设计它们,以便它们仅包含该视图需要处理的特定信息。让映射层处理域实体和视图模型之间的转换。

I was able to follow only the first half of your question. It's the one in which you have showed some code and the one with which I can help you. The second half was a complete mist for me.

So when you want to design a view think of what fields this view needs to display/edit. And design a view model for it:

public class ChangeProfileViewModel
{
    [Required]
    public string Address { get; set; }

    [Required]
    public string City { get; set; }
}

and then have your GET controller action that is supposed to render this view populate the view model:

public ActionResult ChangeProfile()
{
    CustomProfile profile = CustomProfile.GetUserProfile(User.Identity.Name);
    ChangeProfileViewModel model = new ChangeProfileViewModel
    {
        Address = profile.Address,
        City = profile.City
    };
    return View(model);
}

then you design the corresponding view which will be strongly typed to this view model:

@model ChangeProfileViewModel
@using (Html.BeginForm())
{
    @Html.EditorForModel()
    <button type="submit">OK</button>
}

and finally you have a POST controller action that will handle the submission of this form:

[HttpPost]
public ActionResult ChangeProfile(ChangeProfileViewModel model)
{
    if (!Model.IsValid)
    {
        // there were validation errors => redisplay the view
        return View(model);
    }

    // validation succeeded => process the results
    CustomProfile profile = CustomProfile.GetUserProfile();
    profile.Address = model.Address;
    profile.City = model.City;
    profile.Save();
    return RedirectToAction("Profile");
}

Now what we observe here is that in both our GET and POST actions we have repetitive mapping code between our domain model (CustomProfile) and our view model (ChangeProfileViewModel). To solve this issue I may recommend you using AutoMapper. It could simplify your GET action to:

public ActionResult ChangeProfile()
{
    CustomProfile profile = CustomProfile.GetUserProfile(User.Identity.Name);
    ChangeProfileViewModel model = Mapper.Map<CustomProfile, ChangeProfileViewModel>(profile);
    return View(model);
}

or with a custom action filter to even:

[AutoMap(typeof(CustomProfile), typeof(ChangeProfileViewModel))]
public ActionResult ChangeProfile()
{
    CustomProfile profile = CustomProfile.GetUserProfile(User.Identity.Name);
    return View(profile);
}

and your POST action to:

[HttpPost]
public ActionResult ChangeProfile(ChangeProfileViewModel model)
{
    if (!Model.IsValid)
    {
        // there were validation errors => redisplay the view
        return View(model);
    }

    // validation succeeded => process the results
    CustomProfile profile = CustomProfile.GetUserProfile();
    Mapper.Map<ChangeProfileViewModel, CustomProfile>(model, profile);
    profile.Save();
    return RedirectToAction("Profile");
}

What's important to know about view models is that you should always use them for each view and design them in such a way so that they contain only the specific information that this view needs to handle. Leave to the mapping layer handle the conversion between your domain entities and your view models.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文