0

我有一个插入卡片的 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 的不同字段中?我听说过一些关于序列化的事情,但我不知道这对我来说意味着什么!

非常感谢您!

4

2 回答 2

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"}]"

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

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

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

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

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

于 2013-10-16T21:39:58.647 回答
0

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

我的卡片属性的双向绑定不适用于 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>
于 2013-10-19T21:30:41.340 回答