web-dev-qa-db-fra.com

MVC 4 - Utiliser un modèle différent en vue partielle

S'il vous plaît supporter avec mon noobness, je suis super nouveau pour le modèle MVC.

Ce que j'essaie de faire

Je construis une page d'informations de profil pour les utilisateurs enregistrés sur mon site. Cette page listerait des données sur l'utilisateur, telles que sa date de naissance, son numéro de téléphone, son statut d'abonnement, etc. Vous avez l'idée. J'aimerais aussi avoir un formulaire pour permettre aux utilisateurs de changer leur mot de passe, leur adresse email, leurs informations personnelles sur la même page .

Mon problème

Les données de l'utilisateur proviennent de mon contrôleur via une variable de modèle transmise:

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

La sortie ressemble à ceci à mon avis:

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

Le formulaire dans lequel l'utilisateur pourrait modifier ses informations utiliserait un autre modèle, ProfileModel. Donc, de manière générale, je dois utiliser deux modèles, un pour la sortie des informations et un pour la publication des données. Je pensais qu'en utilisant une vue partielle, je pouvais y arriver, mais j'obtiens cette erreur:

L'élément de modèle passé dans le dictionnaire est de type 'Applicense.Models.User', mais ce dictionnaire nécessite un élément de modèle de tapez 'Applicense.Models.ProfileModel'.

Voici à quoi ressemble mon appel à la vue partielle:

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

        @Html.Partial("_ModifyProfileInfo")
    }

Voici la vue partielle:

@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>

Et enfin voici mon 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; }
    }

Est-ce que je manque quelque chose? Quelle est la bonne façon de faire cela?

Edit: J'ai refait mon code reflétant la réponse de Nikola Mitev, mais maintenant, j'ai un autre problème. Voici l'erreur que je reçois:

La référence d'objet n'est pas définie à une instance d'un objet. (@ Model.UserObject.LastName)

Cela se produit uniquement lorsque je publie les valeurs d'adresse de messagerie modifiées. Voici mon 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; }
    }

Manette:

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

            var ProfileViewModel = new ProfileModel
            {
                UserObject = User
            };

            return View(ProfileViewModel);
        }

Et enfin voici ma classe de modèles 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...

Je pense que cela se produit car le modèle tente de placer des données dans chaque colonne required dans la base de données.

Edit2: La méthode httppost de mon action Profil:

[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

Le meilleur moyen de gérer cette situation est d'utiliser et de transmettre viewModel à votre contrôleur de profil. ViewModel est une classe wrapper pour plusieurs objets que vous souhaitez transmettre à votre vue.

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

Votre contrôleur devrait ressembler à:

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);
}

Et enfin votre vue:

@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

Il y a une surcharge de @Html.Partial qui vous permet d'envoyer ViewData tel que défini dans votre contrôleur - c'est la méthode que j'utilise généralement pour les vues partielles . Dans votre contrôleur, définissez ViewData["mypartialdata"] comme ViewDataDictionary. Alors à votre avis

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

Dans votre fonction de profil [HttpPost], si modelstate.isvalid est défini sur false, vous renvoyez votre vue d'édition, mais vous devez définir à nouveau votre pmViewModel. Sinon, votre vue partielle n'aura pas d'objet à afficher. Essayez d'utiliser ce qui suit et dites-nous ce qui se passe 

[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

Bien que je sache que cette question a été posée il y a longtemps, certaines personnes pourraient néanmoins faire face à un problème similaire. Une solution simple que j'utilise pour transmettre ou disposer de plusieurs modèles de vue sur une page consiste à utiliser un ViewBag pour contenir le deuxième objet et y faire référence dans la vue. Voir exemple ci-dessous.

Faites ceci dans votre contrôleur:

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;

Ensuite, à votre avis, ces propriétés deviennent facilement disponibles pour vous

0
john