web-dev-qa-db-ja.com

MVC 4-部分ビューで別のモデルを使用する

noobnessに耐えてください、私はMVCパターンに非常に新しいです。

私がやろうとしていること

私は自分のサイトに登録ユーザー向けのプロファイル情報ページを構築しています。このページには、生年月日、電話番号、サブスクリプションステータスなど、ユーザーに関するデータが一覧表示されます。アイデアが得られます。また、ユーザーが自分のパスワード、メールアドレス、個人情報を変更できるようにするフォームを作成したいと思います同じページ上

私の問題

ユーザーのデータは、渡されたモデル変数を介してコントローラーから取得されます。

public ActionResult Profil()
        {
            var model = db.Users.First(e => e.UserName == WebSecurity.CurrentUserName);
            return View(model);
        }

私の見解では、出力は次のようになります。

<label>Phone number: </label>
            @if (Model.PhoneNumber != null)
                    {
                        @Model.PhoneNumber
                    }
                    else
                    {
                        <span class="red">You haven't set up your phone number yet. </span>
                    }

ユーザーが情報を変更できるフォームは、別のモデルProfileModelを使用します。基本的に、ビューでは2つのモデルを使用する必要があります。1つは情報の出力用、もう1つはデータの投稿用です。部分的なビューを使用してこれを達成できると思いましたが、このエラーが発生します:

ディクショナリに渡されるモデルアイテムのタイプは「Applicense.Models.User」ですが、このディクショナリには「Applicense.Models.ProfileModel」タイプのモデルアイテムが必要です。

パーシャルビューの呼び出しは次のようになります。

 @using (Html.BeginForm())
    {
        @Html.AntiForgeryToken()
        @Html.ValidationSummary()

        @Html.Partial("_ModifyProfileInfo")
    }

部分的なビューは次のとおりです。

@model Applicense.Models.ProfileModel
<ul>
    <li>
        @Html.LabelFor(m => m.Email)
        @Html.EditorFor(m => m.Email)
    </li>
    <li>
        @Html.LabelFor(m => m.ConfirmEmail)
        @Html.EditorFor(m => m.ConfirmEmail)
    </li>
    <input type="submit" value="Update e-mail" />
</ul>

そして最後に私のProfileModelがあります:

public class ProfileModel
    {
        [Required]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "New e-mail address")]
        public string Email { get; set; }

        [DataType(DataType.EmailAddress)]
        [Display(Name = "Confirm new e-mail address")]
        [Compare("Email", ErrorMessage = "The e-mail and it's confirmation field do not match.")]
        public string ConfirmEmail { get; set; }
    }

何か不足していますか?これを行う適切な方法は何ですか?

編集:ニコラ・ミテフの答えを反映してコードを作り直しましたが、今は別の問題があります。ここに私が得るエラーがあります:

オブジェクト参照がオブジェクトインスタンスに設定されていません。 (@ Model.UserObject.LastName)

これは、変更した電子メールアドレスの値を投稿するときにのみ発生します。これが私のViewModel(ProfileModel.cs)です:

public class ProfileModel
    {
        public User UserObject { get; set; }

        [Required]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "Új e-mail cím")]
        public string Email { get; set; }

        [DataType(DataType.EmailAddress)]
        [Display(Name = "Új e-mail cím megerősítése")]
        [Compare("Email", ErrorMessage = "A két e-mail cím nem egyezik.")]
        public string ConfirmEmail { get; set; }

        [DataType(DataType.EmailAddress)]
        [Display(Name= "E-mail cím")]
        public string ReferEmail { get; set; }
    }

コントローラ:

public ActionResult Profil()
        {
            var User = db.Users.First(e => e.UserName == WebSecurity.CurrentUserName);

            var ProfileViewModel = new ProfileModel
            {
                UserObject = User
            };

            return View(ProfileViewModel);
        }

そして最後に、私のuser.csモデルクラス:

[Table("UserProfile")]
    public class User
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int UserId { get; set; }
        [Column("UserName")]
        public string UserName { get; set; }
        [Column("Email")]
        [Required]
        public string Email { get; set; }
        [Column("FirstName")]
        public string FirstName { get; set; }
        [Column("LastName")]
        public string LastName { get; set; }
        [Column("PhoneNumber")]
        public string PhoneNumber { get; set; }
... You get the idea of the rest...

モデルが各required列のデータをデータベースに入れようとしているため、私はそれが起こっていると考えています。

Edit2:プロファイルアクションのhttppostメソッド:

[HttpPost]
        [Authorize]
        [ValidateAntiForgeryToken]
        public ActionResult Profil(ProfileModel model)
        {
            if (ModelState.IsValid)
            {
//insert into database
                return Content("everything's good");
            }
            else
            {
//outputs form errors
                return View(model);
            }
        }
29
PeterInvincible

この状況に対処する最善の方法は、viewModelを使用してProfileコントローラーに渡すことです。viewModelは、ビューに渡す複数のオブジェクトのラッパークラスです。

public class ProfileUserViewModel
{
   public ProfileModel ProfileModelObject {get; set;}
   public UserModel  UserModelObject {get; set;}
}   

コントローラは次のようになります。

public ActionResult Profil()
{            
    var profileModel = db.Users.First(e => e.UserName == WebSecurity.CurrentUserName);
    var userModel = //fetch from db.

    var pmViewModel = new ProfileUserViewModel  
                          {
                              ProfileModelObject = profileModel,
                              UserModelObject = userModel
                          };

   return View(pmViewModel);
}

そして最後にあなたの見解:

@model Applicense.Models.ProfileUserViewModel

<label>Phone number: </label>

@if (Model.ProfileModelObject.PhoneNumber != null)
{
   @Model.PhoneNumber
}
else
{
    <span class="red">You haven't set up your phone number yet. </span>
}
37
Nikola Mitev

コントローラで定義されているViewDataを送信できる@Html.Partialのオーバーロードがあります。これは、私が通常部分ビューに使用する方法です。コントローラーでViewData["mypartialdata"]ViewDataDictionaryとして定義します。その後、あなたの意見で

@Html.Partial("_ModifyProfileInfo",ViewData["mypartialdata"])
13
JamieA

[HttpPost] profil関数で、modelstate.isvalidがfalseの場合、編集ビューを返しますが、pmViewModelを再度定義する必要があります。そうでない場合、部分ビューにはオブジェクトがありません表示。以下を使用してみて、何が起こるか教えてください

[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public ActionResult Profil(ProfileModel model)
{
    if (ModelState.IsValid)
    {
        //insert into database
        return Content("everything's good");
    }
    else
    {
        //outputs form errors
        var pmViewModel = new ProfileUserViewModel  
        {
            ProfileModelObject = profileModel,
            UserModelObject = userModel
        };

        return View(model);
    }
}
1
JamieA

私はこの質問がずっと前に聞かれたことを知っていますが、一部の人々はまだ同様の問題に直面しているかもしれません。 1つのページに複数のビューモデルを渡すまたは使用する簡単な解決策の1つは、ViewBagを使用して2番目のオブジェクトを保持し、ビュー内でそれを参照することです。以下の例を参照してください。

コントローラーでこれを行います:

Obj2 personalDets = new Obj2();
DbContext ctx = new DbContext();
var details = ctx.GetPersonalInformation;

foreach(var item in details) {
    personalDets.Password = item.Password;
    personalDets .EmailAddress = item.EmailAddress; 
}

ViewBag.PersonalInformation = personalDets;

その後、ビューでこれらのプロパティがすぐに利用可能になります

0
john