asp.net-mvc - Persistance des préférences de colonne jqGrid




asp.net-mvc-3 (2)

J'ai quelques jqGrids sur mon application ASP.NET MVC 3 avec plusieurs colonnes. J'ai ajouté aux définitions de colonnes suivantes certaines colonnes à masquer par défaut:

colModel: [
   { name: 'IceCreamID', hidden: true},
   { name: 'RecipeID', hidden: true }

et cela fonctionne bien. Ces colonnes ne sont pas visibles sur ma grille.

Ensuite, j'ai ajouté ceci pour implémenter le sélecteur de colonne:

var grid = $('#icecreamGrid');
grid.jqGrid('navButtonAdd', '#icecreamPager',
{ caption: "Columns", buttonicon: "ui-icon-calculator",
  title: "Choose Columns",
  onClickButton: function() {
     grid.jqGrid('columnChooser');
  }
});

Génial, fait apparaître le sélecteur de colonne maintenant. J'ai ensuite ajouté ce qui suit aux colonnes que je n'ai jamais voulu afficher dans le sélecteur de colonne:

colModel: [
   { name: 'IceCreamID', hidden: true, hidedlg: true},

Je peux donc maintenant masquer / afficher les colonnes correctement. Maintenant, comment persisteriez-vous cette information? DB? En tant que cookie? Autrement? Existe-t-il un moyen privilégié de stocker ce type d’informations qui est en réalité une préférence de l’utilisateur plutôt que quelque chose lié aux données elles-mêmes?

Plus d'informations

Sur la base du commentaire d'Oleg ci-dessous, je veux fournir un peu plus d'informations.

Le point ici est que j'ai des grilles avec 10-15 colonnes qui pourraient être affichées en fonction des préférences de l'utilisateur. Pour un exemple simple, une de mes grilles comporte les 9 colonnes suivantes:

IceCream|ShortName|HasNuts|SugarAdded|LimitedRun|PromoItem|Facility|FirstRun|LastRun

Les utilisateurs peuvent masquer / afficher l'une de ces 9 colonnes en fonction de leurs préférences personnelles.

Ce que je veux faire, c'est fournir un moyen de persister les colonnes qu'un utilisateur particulier souhaite voir afin de ne pas avoir à choisir de nouveau les colonnes à afficher à chaque fois que la page avec cette grille est affichée.


Answers

J'ai trouvé votre question très intéressante. La question de la sauvegarde de l'état utilisateur de la grille est intéressante dans de nombreux cas. Il y a des réponses intéressantes sur ces problèmes qui utilisent des cookies (voir here par exemple).

À mon avis, sauvegarder l'état de la grille dans la base de données sur le serveur ou dans le localStorage est préférable à l'utilisation de cookies. Le meilleur moyen dépend des exigences du projet dans lequel vous l'utilisez. Par exemple, l'utilisation du stockage de base de données sur le serveur vous permet de mettre en œuvre l'état d'itinérance de la grille. Si vous utilisez localStorage au lieu de cookies, les préférences de l'utilisateur seront perdues si l'utilisateur accède à un autre ordinateur ou si l'utilisateur utilisera un autre navigateur Web sur le même ordinateur.

Un autre problème avec l'état de la grille est la maintenance. Les informations sur les colonnes de la grille que vous détenez généralement dans les fichiers JavaScript ou HTML et non dans la base de données. Dans le cas où les deux sources peuvent ne pas être synchrones sur les modifications de la grille. Différents scénarios du problème de mise à jour pourraient vous sembler faciles à imaginer. Néanmoins, les avantages des préférences des utilisateurs sont si importants dans certains scénarios que les problèmes avec de petits inconvénients ne sont pas si importants et peuvent être résolus relativement facilement.

Je vais donc consacrer du temps à la mise en œuvre de deux démos qui montrent comment cela peut être mis en œuvre. J'ai utilisé localStorage dans mes démos pour plusieurs raisons. Je n'en mentionne que deux:

  1. Les cookies sont la manière d'envoyer des informations différentes de manière permanente vers ou depuis le serveur, ce qui n'est pas vraiment nécessaire. Il augmente la taille de l’en-tête HTTP et diminue les performances du site Web (voir here par exemple).
  2. Les cookies ont des restrictions très strictes. Correspond à la section 6.3 de rfc2109 ou 6.1 de rfc6265: au moins 4096 octets par cookie, au moins 50 cookies par domaine (20 en rfc2109), au moins 3000 cookies au total (300 en rfc2109). Donc, les cookies on ne peut pas utiliser pour enregistrer trop d'informations. Par exemple, si vous sauvegardez l'état de chaque grille de chaque page Web, vous pouvez rapidement atteindre les limites.

De l'autre côté, localStorage est pris en charge par tous les navigateurs modernes et sera pris en charge dans Internet Explorer à partir d'IE8 (voir here ). Le localStorage sera automatiquement enregistré par origine (comme a1.example.com, a2.example.com, a3.example.com, etc.) et aura une limite arbitraire de 5 Mo par origine (voir here ). Donc, si vous utilisez l’espace avec soin, vous serez loin des limites.

Donc, j'ai utilisé dans mes démos le localStorage . Je devrais également mentionner que certains plugins comme jStorage utilisent localStorage si celui-ci est supporté par le navigateur et utilisent un autre stockage, mais la même interface pour vous dans le cas d’anciens navigateurs comme IE6 / IE7. Dans le cas où vous avez seulement une taille de stockage inférieure: 128 Ko au lieu de 5 Mo, mais cela vaut mieux que 4 Ko pour les cookies (voir here ).

Maintenant sur la mise en œuvre. Je crée deux démos: this et sa version étendue: this .

Dans this démo, les états de grille suivants seront enregistrés et automatiquement restaurés sur le rechargement de la page ( F5 dans la plupart des navigateurs Web):

  • quelle colonne est cachée
  • l'ordre des colonnes
  • la largeur de chaque colonne
  • le nom de la colonne par laquelle la grille sera triée et le sens du tri
  • le numéro de la page en cours
  • le filtre actuel de la grille et l'indicateur si le filtre est appliqué. J'ai utilisé multipleSearch: true réglage dans la grille.

De la même manière, on peut étendre (ou réduire) la liste des options qui font partie de l’état de grille enregistré.

Les parties les plus importantes du code de la démo que vous trouverez ci-dessous:

var $grid = $("#list"),
    saveObjectInLocalStorage = function (storageItemName, object) {
        if (typeof window.localStorage !== 'undefined') {
            window.localStorage.setItem(storageItemName, JSON.stringify(object));
        }
    },
    removeObjectFromLocalStorage = function (storageItemName) {
        if (typeof window.localStorage !== 'undefined') {
            window.localStorage.removeItem(storageItemName);
        }
    },
    getObjectFromLocalStorage = function (storageItemName) {
        if (typeof window.localStorage !== 'undefined') {
            return $.parseJSON(window.localStorage.getItem(storageItemName));
        }
    },
    myColumnStateName = 'ColumnChooserAndLocalStorage.colState',
    saveColumnState = function (perm) {
        var colModel = this.jqGrid('getGridParam', 'colModel'), i, l = colModel.length, colItem, cmName,
            postData = this.jqGrid('getGridParam', 'postData'),
            columnsState = {
                search: this.jqGrid('getGridParam', 'search'),
                page: this.jqGrid('getGridParam', 'page'),
                sortname: this.jqGrid('getGridParam', 'sortname'),
                sortorder: this.jqGrid('getGridParam', 'sortorder'),
                permutation: perm,
                colStates: {}
            },
            colStates = columnsState.colStates;

        if (typeof (postData.filters) !== 'undefined') {
            columnsState.filters = postData.filters;
        }

        for (i = 0; i < l; i++) {
            colItem = colModel[i];
            cmName = colItem.name;
            if (cmName !== 'rn' && cmName !== 'cb' && cmName !== 'subgrid') {
                colStates[cmName] = {
                    width: colItem.width,
                    hidden: colItem.hidden
                };
            }
        }
        saveObjectInLocalStorage(myColumnStateName, columnsState);
    },
    myColumnsState,
    isColState,
    restoreColumnState = function (colModel) {
        var colItem, i, l = colModel.length, colStates, cmName,
            columnsState = getObjectFromLocalStorage(myColumnStateName);

        if (columnsState) {
            colStates = columnsState.colStates;
            for (i = 0; i < l; i++) {
                colItem = colModel[i];
                cmName = colItem.name;
                if (cmName !== 'rn' && cmName !== 'cb' && cmName !== 'subgrid') {
                    colModel[i] = $.extend(true, {}, colModel[i], colStates[cmName]);
                }
            }
        }
        return columnsState;
    },
    firstLoad = true;

myColumnsState = restoreColumnState(cm);
isColState = typeof (myColumnsState) !== 'undefined' && myColumnsState !== null;

$grid.jqGrid({
    // ... other options
    page: isColState ? myColumnsState.page : 1,
    search: isColState ? myColumnsState.search : false,
    postData: isColState ? { filters: myColumnsState.filters } : {},
    sortname: isColState ? myColumnsState.sortname : 'invdate',
    sortorder: isColState ? myColumnsState.sortorder : 'desc',
    loadComplete: function () {
        if (firstLoad) {
            firstLoad = false;
            if (isColState) {
                $(this).jqGrid("remapColumns", myColumnsState.permutation, true);
            }
        }
        saveColumnState.call($(this), this.p.remapColumns);
    }
});
$grid.jqGrid('navButtonAdd', '#pager', {
    caption: "",
    buttonicon: "ui-icon-calculator",
    title: "choose columns",
    onClickButton: function () {
        $(this).jqGrid('columnChooser', {
            done: function (perm) {
                if (perm) {
                    this.jqGrid("remapColumns", perm, true);
                    saveColumnState.call(this, perm);
                }
            }
        });
    }
});
$grid.jqGrid('navButtonAdd', '#pager', {
    caption: "",
    buttonicon: "ui-icon-closethick",
    title: "clear saved grid's settings",
    onClickButton: function () {
        removeObjectFromLocalStorage(myColumnStateName);
    }
});

Soyez myColumnStateName pour définir myColumnStateName (la valeur «ColumnChooserAndLocalStorage.colState») dans la démo) à différentes valeurs sur les différentes pages.

this est l’extension du premier utilisant la technique de mon ancienne réponse à votre autre question. La démo utilise la barre d'outils de recherche et synchronise les informations supplémentaires entre le formulaire de recherche avancée et la barre d'outils de recherche.

MISE À JOUR : La réponse suivante contient une version étendue du code inclus ci-dessus. Il montre comment conserver les lignes (ou lignes) sélectionnées en plus. Une autre réponse montre comment conserver la liste des noeuds étendus de la grille de l'arborescence et développer les noeuds lors de la remise à neuf de la page.


Je commence avec une installation prête à l'emploi de MVC5 et utilise AutoFac comme conteneur IoC. On dirait que j'essaie d'atteindre un objectif similaire à vous, alors laissez-moi vous expliquer ce que j'ai fait. En tant que déni de responsabilité, l'utilisation d'IoC et d'Identity est relativement nouvelle pour moi.

Je pense que le contexte IOwin est inutile dans un rôle de CIO si vous utilisez le vôtre. Je suis passé à l’enregistrement de mon ApplicationUserManager avec AutoFac. Pour y parvenir, je devais:

Supprimez les lignes CreatePerOwinContext de Startup.Auth, car je vais enregistrer ApplicationDbContext et ApplicationUserManager dans AutoFac.

//app.CreatePerOwinContext(ApplicationDbContext.Create);
//app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

Modifiez les arguments du constructeur ApplicationUserManager et incluez tous les éléments de la fonction Create.

public ApplicationUserManager(IUserStore<ApplicationUser> store, IdentityFactoryOptions<ApplicationUserManager> options)
        : base(store)
{
    //all the code from the 'Create' function here, using `this` for `manager`
}

Définissez AccountController pour qu'un constructeur unique prenne un ApplicationUserManager en tant qu'argument et élimine la propriété UserManager qui récupère ApplicationUserManager de OwinContext .

private ApplicationUserManager _userManager; //every thing that needs the old UserManager property references this now
public AccountController(ApplicationUserManager userManager) 
{
    _userManager = userManager;
}

Enregistrez tout avec AutoFac, y compris une instance de IdentityFactoryOptions.

var x = new ApplicationDbContext();
builder.Register<ApplicationDbContext>(c => x);
builder.Register<UserStore<ApplicationUser>>(c => new UserStore<ApplicationUser>(x)).AsImplementedInterfaces();
builder.Register<IdentityFactoryOptions<ApplicationUserManager>>(c => new IdentityFactoryOptions<ApplicationUserManager>()
{
    DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("ApplicationName")
});
builder.RegisterType<ApplicationUserManager>();

C'est le résumé approximatif. J'ai peut-être manqué quelques autres réglages que j'ai dû faire en cours de route.





asp.net-mvc asp.net-mvc-3 jqgrid