【问题标题】:LocalStorage of contenteditable content (AngularJS)内容可编辑内容的本地存储 (AngularJS)
【发布时间】:2013-10-20 05:30:41
【问题描述】:

我有一个插入卡片的 AngularJS 小工具。 我的目标是将它们存储在本地。我为卡片数组解决了这个问题,但不是卡片内容,即“内容可编辑” 你能帮我解决这个问题并给我一些最佳实践解决方案吗?

这是一个 Plunker(在 JS 中)(红色大按钮删除 localStorage。一定要打开一个大窗口):http://plnkr.co/edit/SlbWZ5Bh62MDKWViUsMr

这是我的代码(使用 CoffeeScript。对于 JS,请参阅上面的 Plunker):

这是用户输入的标记

<div class="card card-{{ card.color }}">
    <header>
        <p class="points" contenteditable></p>
        <p class="number" contenteditable>#</p>
        <h2 class="customerName"  contenteditable>{{ card.customer.name }}</h2>
        <h3 class="projectName" contenteditable>Project Name</h3>
    </header>
    <article>
        <h1 class="task" contenteditable>Title</h1>
        <p class="story" contenteditable>Description</p>
    </article>
    <footer>
        <div class="divisions">
        <p class="division"></p>
        <button ng-click="deleteCard()" class="delete">X</button>
        </div>
    </footer>
</div>
<div class="card card-{{ card.color }} backside">
    <article>
        <h2 class="requirement">Requirements</h2>
        <p contenteditable></p>
    </article>
</div>

在这里您可以看到我在上面的控制器中为卡片数组设置的 localStorage:

Card = (@color, @customer) ->

        $scope.cards = []

        json = localStorage.getItem "cards"
        getCards = JSON.parse(json) if json?
        $scope.cards = $scope.cards.concat getCards if getCards?

        $scope.reset = ->
            localStorage.clear()

        $scope.save = ->
            cards = []
            for card in $scope.cards
                cards.push
                    color: card.color
                    customer:
                        name: card.customer.name

            localStorage.setItem "cards", JSON.stringify(cards)

        $scope.addCardRed = (customer) ->
            $scope.cards.push new Card("red", customer)
            $scope.save()

如何将用户输入存储在 localStorage 的不同字段中?我听说过一些关于序列化的事情,但我不知道这对我来说意味着什么!

非常感谢您!

【问题讨论】:

    标签: angularjs local-storage angularjs-directive web-storage


    【解决方案1】:

    您可以将ng-model 指令与任何contenteditable 字段一起使用,就像使用输入或文本区域一样。因此,与其尝试使用 {{...}} 大括号将模型绑定到视图,不如使用 ng-model,然后将可编辑的 DOM 元素视为表单中的字段。

    例如,在你看来:

    <header ng-repeat="card in cards">
        <!-- These are just sample fields for the card object, but you can modify them -->
        <p class="points" contenteditable ng-model="card.points"></p>
        <p class="number" contenteditable ng-model="card.number"></p>
        <h2 class="customerName"  contenteditable ng-model="card.customer.name"></h2>
        <h3 class="projectName" contenteditable ng-model="card.projectName"></h3>
    </header>
    

    然后在您的控制器中,您将模型附加到$scope,就像您已经使用$scope.cards = $scope.cards.concat getCards if getCards? 完成的那样。这会将您的 cards 模型双向绑定到控制器的范围。

    然后在您的控制器中,要镜像LocalStorage 中的模型数据,您可以使用以下方式自己完成:

    在你的控制器中:

    ....
    //  for example's sake
    $scope.cards = [  // the cards array would look something like this
        {points: 0, number: 5, customer: {name: 'bob'}, projectName: 'myProj1'},
        {points: 1, number: 6, customer: {name: 'joe'}, projectName: 'myProj2'},
        {points: 2, number: 7, customer: {name: 'bill'}, projectName: 'myProj3'},
        {points: 3, number: 8, customer: {name: 'jerry'}, projectName: 'myProj4'}
    ];
    ....
    // listen to all changes to the $scope.cards array
    $scope.$watch('cards', function(newVal){
        var str = angular.toJson(newVal); // serialize the cards array into a string
        // NOTE: the 'someKey' string is the key that you'll use later to retrieve it back
        window.localStorage['someKey'] = str;  // store the serialized string in localStorage
    }, true);
    ....
    

    在上面的例子中,angular.toJson(newVal) 将采用newVal 变量(这只是对“最近更新”卡片数组的引用),并将其序列化为 JSON 字符串(即 angular.toJson 基本上是换行原生JSON.stringify() 方法)。为了将javascript对象放入LocalStorage,它必须被序列化为字符串,因为您只能将原语作为LocalStorage键中的值。

    所以newVal 将被放入localStorage,看起来像这样:

    "[{"points":0,"number":5,"customer":{"name":"bob"},"projectName":"myProj1"},{"points":1,"number":6,"customer":{"name":"joe"},"projectName":"myProj2"},{"points":2,"number":7,"customer":{"name":"bill"},"projectName":"myProj3"},{"points":3,"number":8,"customer":{"name":"jerry"},"projectName":"myProj4"}]"
    

    然后稍后(无论何时需要),您都可以使用以下命令再次从 localStorage 检索 cards 数组:

    var str = window.localStorage['someKey'];
    $scope.cards = angular.fromJson(str);
    

    或者您可以使用库来进行序列化/保存,如下所示:https://github.com/grevory/angular-local-storage。我从未使用过它,但它完全符合您的要求。

    希望这有助于澄清一些事情。

    更新:这超出了这个问题的范围,但既然你问了。听起来你没有掌握ng-repeatng-model 指令的概念。这些可能是 Angular 中最著名(也是使用最广泛)的两个指令。通过结合这两个指令(如上面的视图示例),当用户在您的视图中编辑数据时,它将自动使您的模型(即$scope.cards)和您的视图(即&lt;header&gt;)保持同步。 ng-repeat 将“自动”为您的 cards 数组中的每个 card 创建一个新的标题元素(因此是 ng-repeat="card in cards")。因此,当添加新卡片或从卡片数组中删除卡片时,Angular 将根据需要添加或删除 &lt;header&gt; 元素。然后,使用 contenteditableng-model 指令,Angular 会将这些可编辑 DOM 元素的内容绑定到每张卡片的值。通常ng-model 与表单元素(即输入/文本区域/选择)一起使用,但它也可以用于任何可编辑字段。将您的可编辑元素视为输入,然后仔细查看 Angular 文档 found here 中的 &lt;input ng-model="" /&gt; 示例。这应该会有所帮助。

    【讨论】:

    • 我仍然不确定如何实现它。你能给我另一个提示吗?我必须将模型附加在 Card 对象中还是外部?你能给我一个例子,我如何存储我的 contenteditable 内容吗?不知何故,我还没有完全理解整个 localStorage 和序列化的工作原理:-/ 如果您能帮助我,我将不胜感激!非常感谢您!
    • 我添加了更多解释,使我之前的回答更加冗长。如果您仍然感到困惑,请告诉我。
    • 你太棒了!感谢您的新回复。现在我明白了很多。仍然令人头疼的是如何使用卡片数组属性,因为一些数据已经存在,当我添加一张新卡片时,卡片数组的一些数据会在用户放入某些内容后添加。此外,卡片数组(如何你在上面填写)首先是空的,对吧?我的空卡数组如何与客户等已经设置的值一起使用?至少我了解 $watch 和存储的东西,谢谢:)
    【解决方案2】:

    现在我知道是什么让我困惑了!

    我的卡片属性的双向绑定不适用于 contenteditable。我删除了每个 contenteditable 属性,而不是 p、h2 等,我用输入标签替换了标签。这对我来说很好。

    感谢您的耐心和出色的解释,@tennisagent!对于 $watch 提示!非常感谢您的帮助:)

    这是我对控制器的解决方案:

    angular.controller 'CustomerController', ($scope)   ->
    
        $scope.customers = [
            { name: "name1" }
            { name: "name2" }
            { name: "name3" }
        ]
    
        $scope.cards = []
    
        Card = (@color, @customer, @points, @number, @projectName, @story) ->
    
        $scope.$watch 'cards', ((newValue) ->
            string = angular.toJson(newValue)
            localStorage["cards"] = string
        ), true
    
        json = localStorage["cards"]
        parsedCards = angular.fromJson(json) if json?
        $scope.cards = $scope.cards.concat parsedCards if parsedCards?
    
    
        $scope.reset = ->
            localStorage.clear()
            sessionStorage.clear()
    
            $scope.cards = []
    
        $scope.addCardRed = (customer) ->
            $scope.cards.push new Card("red", customer)
    

    这是我的标记解决方案:

    <div class="card card-{{ card.color }}">
        <header>
            <input class="points" contenteditable ng-model="card.points"></input>
            <input class="number" placeholder="#" contenteditable ng-model="card.number"></input>
            <input class="customerName"  contenteditable ng-model="card.customer.name"></input>
            <input class="projectName" placeholder="Projekt" contenteditable ng-model="card.projectName"></input>
        </header>
        <article>
            <input class="task" placeholder="Titel" contenteditable ng-model="card.task"></input>
            <textarea class="story" placeholder="Story" contenteditable ng-model="card.story"></textarea>
        </article>
        <footer>
            <div class="divisions">
                <p class="division"></p>
                <button ng-click="deleteCard()" class="delete">X</button>
            </div>
        </footer>
    </div>
    <div class="card card-{{ card.color }} backside">
        <article>
            <h2 class="requirement">Requirements</h2>
            <textarea class="requirements" placeholder="Aspects" contenteditable ng-model="card.requirements"></textarea>
        </article>
    </div>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-22
      • 1970-01-01
      • 2013-03-05
      • 2013-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多