Archives de Catégorie: MVC Razor

Liste des erreurs MVC Razor

Voici une liste des erreurs que j’ai pu rencontrer lors d’une mission en MVC Razor.


DataBinding : ‘MVC3_Razor.Models.User’ ne comporte pas de propriété appelée ‘Libelle’.

Erreur :

Users = new SelectList(db.User, "UserID", "Libelle");

Correction :

Users = new SelectList(db.User, "UserID", "Name");

LINQ to Entities ne reconnaît pas la méthode « System.String ToString() »

Erreur :

Projets = db.Projet.Select(x => new SelectListItem
                {
                    Value = x.ProjetID.ToString(),
                    Text = x.Libelle
                }),

Correction :

Projets = new SelectList(db.Projet, "ProjetID", "Libelle");

Il n’y a aucun élément ViewData de type ‘IEnumerable’ avec la clé ‘TacheID’.

Correction :
Mettre un ViewBag.TacheID dans le controller.


L’élément ViewData avec la clé ‘ProjetID’ est de type ‘System.Int32’ mais doit être de type ‘IEnumerable’.

Source correction StackOverflow

Une fois créer dans le Controleur, le ViewBag (ou le modèle) se décharge dans la DropDownList, puisqu’il ont le même nom.
Il faut donc recharger les données avant de rappeler la page (dans le controleur)

Publicités

Gérer les virgules et les points avec les validateur Razor

Etant français, je voulais que mon projet en MVC3 Razor accepte aussi bien les virgules que les points pour les nombres décimaux que je pouvais saisir. J’ai chercher durant un petit moment différentes techniques afin de parvenir à mes fins.
Ce n’est qu’après quelques heures, que je suis tombé sur ce site ce site. Très bien expliquer, il m’a permis de pas mal avancé sur le problème.

Il a suffit de ré-écrire la méthode de vérifcation avec les quelques arrangement qui vont mieux.

/* ----- methods_fr.js ----- */
/*
* Localized default methods for the jQuery validation plugin.
* Locale: FR
*/
$.extend($.validator.methods, {
    min: function (value, element, param) {
        return this.optional(element) || replaceComma(value) >= replaceComma(param);
    },
    max: function (value, element, param) {
        return this.optional(element) || replaceComma(value) = replaceComma(param[0]) && value <= replaceComma(param[1]));
    },
    date: function (value, element) {
        return this.optional(element) || /^\d\d?\.\d\d?\.\d\d\d?\d?$/.test(value);
    },
    number: function (value, element) {
        return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)(?:,\d+)?$/.test(value) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
    }
});

function replaceComma(value) {
    // Quick & Dirty replace ',' by '.' as decimal separators
    return value.replace(',', '.');
}

Ceci permet lors de la vérification « en direct » de ne pas indiqué en rouge, un nombre qui possède une virgule ou un point.

Ensuite, il faut lors de la validation finale transformer les ‘.’ en ‘,’ , puisque nous somme en France, c’est la virgule qui est le séparateur des nombres décimaux. Dans mon cas, je ne vérifie qu’un seul champ monNombre. A vous d’être inventif si vous en avez plusieurs.

function validate() {
    var valueBefore = $("#monNombre").val();
    var valueAfter = valueBefore.replace('.', ',');
    $("#monNombre").val(valueAfter);
}

Il ne reste plus qu’a relier cette fonction à notre submit et d’importer nos scripts (validate et unobtrusive sont les scripts par défaut de Razor). Et attention à l’ordre qui reste très important.

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/methods_fr.js")" type="text/javascript" ></script>

Enfin on vérifie dans le web.config, si la culture fr-FR est bien indiqué.

<system.web>
  <globalization culture="fr-FR" uiCulture="fr-FR" enableClientBasedCulture="false" />
  ...

Raccourcir un texte en Razor

La méthode est simple, mais qu’est-ce qu’elle peut-être utile lors de la génération de tableau. Si votre texte est trop long, voici une petite astuce :

@(item.Description != null ? item.Description.Substring(0, item.Description.Length > 40 ? 40 : item.Description.Length) + "..." : "")

Et avec la gestion des infobulles en css, ça rend plutôt pas mal.

<td class="infobulle">
    @(item.Description != null ? item.Description.Substring(0, item.Description.Length > 40 ? 40 : item.Description.Length) + "..." : "")
    <span>@item.Description</span>
</td>

Création de clé primaire composé en MVC3

Vous avez une table jointe, voiçi comment déclarer les clé primaires composé en MVC3.

Il suffit de les définir dans le Context comme ceçi :

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<RencontreClass>().HasKey(t => new { t.UserId, t.ClientId });
}

Source

Utilisation d’Ajax en MVC Razor

En MVC3 Razor, pour avoir un petit peu d’événementiel dans les pages, vous allez être obligé de passé par les fonctions JavaScript et notamment Ajax pour interagir avec vos controllers.

D’abord un cas simple (1 variable en entrée, 1 variable en sortie):
Controller

[HttpPost]
public string MyFonction(int myVar = 0)
{
    // ...
    String sView = "Halo";
    return sView;
}

View

function toto(){
    $.ajax({
        type: "POST",
        url: '@Url.Action("MyFonction")',
        data: '{myVar : @Model.Foo}',
        success: function (result){
            // ...
        },
        error: function (req, status, error) {
            // ...
        }
    });
}

La partie « error » n’est pas obligatoire, mais pour tester une première fois, ça peut-être utile.

Et maintenant corsons un peu les choses avec plusieurs variables en entrée :
Controller
Côté controller c’est du classique avec :

[HttpGet]
public ActionResult MyFonction2(int myVar1, string myVar2, DateTime myVar3)
{
    // ...
    return Json(result, JsonRequestBehavior.AllowGet);
}

View
Côté Vue, on va passé par du JSON pour transmettre toutes les informations.

function tata() {
    var strJson = {
        myVar1: $(foo).val(),
        myVar2: $(bar).val(),
        myVar3: $(baz).val()
    };

    $.ajax({
        type: "GET",
        url: '@Url.Action("MyFonction2")',
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        data: strJson,
        success: function (result) {
            // ...
        }
    });
}

Si vous souhaitez retourner à la vue plusieurs valeur, je vous conseillerai de passé par un tableau et de l’utiliser de manière standard (result[0]…).

UPDATE 25/10/2012

IE (dans ses versions 7 et 8) est un navigateur ultra agressif avec le cache en Ajax. Si vous posez une question avec les mêmes paramètres d’entrée, il considèrera qu’il possède déjà la réponse. Vous avez donc 2 possibilités, rajouter un paramètres aléatoire à la fin (c’est pas très propre) ou alors rajouter parmi les options de la commande AJAX:

cache : false,

Peuplement du DropDownList

Pour le peuplement d’une DropDownList avec Razor pour du MVC directement dans la page cshtml.

Je vous propose deux solutions qui rempliront une DDL avec des nombres de 0 à 100 et un pas de 5 :

La première, la plus simple, on pose simplement à l’endroit souhaité :

@Html.DropDownListFor(model => model.Pourcentage, new SelectList(Enumerable.Range(0, 100).Where(i => i % 5 == 0))) %

C’est simple, utilise les expressions lambda.

Et pour ceux qui ne sont pas fan, voici la version plus longues, mais tout aussi efficaces :

@{
    List<SelectListItem> list = new List<SelectListItem>(); 
        for (int i = 0; i <= 100; i+=5) 
        {     
            list.Add(new SelectListItem { 
                Text = i.ToString(),
                Value = i.ToString()
            });
        }
}

@Html.DropDownListFor(x => x.Pourcentage, list) %

DropDownList en Cascade – MVC Razor

Voici une petit tutorial pour créer un effet de cascade sur les DropDownList en MVC Razor.

Nous partirons sur un modele de Marque et de Voiture. Simple. Marque 1.n –> 1.1 Voiture. Avec ID et Libelle.
Déjà nous avons besoin dans la vue de 2 DropDownList.

Vue :

@Html.DropDownListFor(model => model.MarqueID, Model.Marques, new { onChange = "MarqueDDL()"})
@Html.ValidationMessageFor(model => model.MarqueID)

@Html.DropDownListFor(model => model.VoitureID, Model.Voitures)
@Html.ValidationMessageFor(model => model.VoitureID)

Vous pouvez passez par le ViewBag, personnellement j’ai opter pour une ViewModel plus simple.

Ensuite chargons les valeurs dans le contrôleur lors de l’appelle de la page. :
Controller :

model.MarqueID = 0;
model.Marques = new SelectList(db.Marque, "MarqueID", "Libelle", model.MarqueID);
model.Voitures = new SelectList(db.Voiture.Where(x => x.MarqueID == model.MarqueID), "VoitureID", "Libelle");

On retourne dans la Vue pour implementer la fonctions de cascade :
Vue

function ProjetDDL() {
    var DDLparent = '#MarqueID'
    var DDLchild = '#VoitureID'
    cascade('@Url.Action("getVoitures")', 'marqID', $(DDLchild), false, DDLparent );
}

function cascade(url, paramName, childSelect, childCascade, parent) {
    var selectedValue = $(parent).val();
    var params = {};
    params[paramName] = selectedValue;

    childSelect.empty();
    $.getJSON(url, params, function (items) {
        $.each(items, function (index, item) {
            childSelect.append($('').attr('value', item.Id).text(item.Name));
            if (item.Selected) {
                $(childSelect).children().last().attr("selected", true);
            }
        });
        if (childCascade) { childSelect.change(); }
    });
}

La fonction cascade est une adaptation du script que l’on peut trouver ici.
Cette fonction demande les paramètres suivant : l’URL de la fonction qui retournera la nouvelle liste à afficher (voir çi-dessous), le nom paramètre d’entrée (et non sa valeur), la DropDownList à peupler, si la DropDownList peupler va entraîner une nouvelle cascade, et la DropDownList qui vient d’être modifier.

Et nous retournons dans le contrôleur pour renvoyé à la vue les valeurs de la DropDownList enfant.

Controller

[HttpGet]
public ActionResult getVoitures(int marqID)
{
    //Récupération via un paramètre
    //Id et Name sont obligatoire, même pour des Enumerable
    var voitures = db.Voiture.Where(x => x.MarqueID == marqID).Select(
        x => new
        {
            Id = x.LotID,
            Name = x.Libelle
        });
    return Json(voitures, JsonRequestBehavior.AllowGet);
}

Vous remarquerez que le nom de la variable d’entrée est celle qui a été indiqué dans la fonction en JS cascade().

Petit bonus, si vous souhaitez préselectionner une valeur dans la DropDownList enfant, il suffit lors de la création de la SelectList d’indiqué le paramètre Selected à true comme ceçi :

var voitures = db.Voiture.Where(x => x.MarqueID == marqID).Select(
    x => new
    {
        Id = x.VoitureID,
        Name = x.Libelle,
        Selected = x.MiseEnAvant == true ? true : false
    });

Dans cet exemple, j’ai une variable MiseEnAvant de type bool, mais ça pourrait être un int, un string une valeur par défaut.

Update : Problème de Cache sous IE 7 – 8

Voir en bas de ce billet précédent