I have a little AngularJS tool that inserts cards. My goal is to store them locally. I worked that out for the cards array, but not for the card content, that is "contenteditable" Can u help me with this and give me some best practice solutions?
Here's a Plunker (in JS) for that (the red big button deletes the localStorage. Be sure to have a wide window open): http://plnkr.co/edit/SlbWZ5Bh62MDKWViUsMr
This is my code (with CoffeeScript. For JS see the Plunker above):
This is the markup for the user input
<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>
Here you see my localStorage setup for the cards array that was in my controller above:
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()
How do I store the user inputs in the different fields in localStorage? I heards something about serialization, but I don't know what it means in my case!
Thank you so much in advance!
You can use the ng-model
directive with any contenteditable
field, just like you would do with an input or textarea. so, instead of trying to use the {{...}}
braces to bind your model to your view, you should just use ng-model
, and then just treat your editable DOM elements as if they were fields in a form.
For example, in your view :
<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>
And then in your controller you would attach the model to the $scope
as you've already done using $scope.cards = $scope.cards.concat getCards if getCards?
. This will two-way bind your cards
model to your controller's scope.
And then in your controller, to mirror the model data in LocalStorage
, you can do it yourself using something like this:
In your controller:
....
// 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);
....
In the above example, the angular.toJson(newVal)
will take the newVal
variable (which is just a reference to the "recently updated" cards array), and will serialize it into JSON string (ie angular.toJson
just basically wraps the native JSON.stringify()
method). In order to put a javascript object into LocalStorage
it must be serialized to a string because you can only put primitives as the value in a LocalStorage
key.
So the newVal
will get put into localStorage
looking 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"}]"
And then later (whenever you need it) you can retrieve the cards
array from localStorage
again using the following:
var str = window.localStorage['someKey'];
$scope.cards = angular.fromJson(str);
Or you can use a library to do the serialization/saving like this one: https://github.com/grevory/angular-local-storage. I've never used it but it does exactly what you want it to.
Hopefully that helps clarify things a bit.
UPDATE: This is beyond the scope of this question, but since you asked. It sounds like your'e not grasping the concept of the ng-repeat
and ng-model
directives. These are probably the two most famous (and most widely used) directives in Angular. By combining these two directives (as in the view example above), it will automatically keep your model (ie $scope.cards
) and your view (ie <header>
) in sync as users edit the data in your view. ng-repeat
will "automagically" create a new header element for every card
in your cards
array (hence the ng-repeat="card in cards"
). So as new cards get added or cards are removed from the cards array, Angular will add or remove <header>
elements as needed. Then, using the contenteditable
and ng-model
directives, Angular will bind the content of those editable DOM elements to the values for each card. Typically ng-model
is used with form elements (ie inputs/textareas/selects) but it can also be used for any editable field. Think of your editable elements as if they were an input, and then take a good long look at the <input ng-model="" />
example from the angular docs found here. That should help.