OLD | NEW |
(Empty) | |
| 1 <h1 id="lab_5_manage_data">Lab 5 - Manage Data</h1> |
| 2 |
| 3 <p>The <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/l
ab3_mvc/angularjs/withcontroller/controller.js#L2-L4">sample from Lab 3</a> uses
a static array of Todos. Every time your app restarts, whatever you've chan
ged is lost. In this section, we will save every change using <a href="http://de
veloper.chrome.com/trunk/apps/storage.html">chrome.storage.sync</a>. This lets y
ou store <em>small things</em> that automatically sync to the cloud if you are o
nline and logged in to Chrome. If you are offline or unlogged, it saves locally
and transparently: you don't have to handle online check and offline fallbac
k in your application.</p> |
| 4 |
| 5 <h2 id="you_should_also_read">You should also read</h2> |
| 6 |
| 7 <p><a href="http://developer.chrome.com/apps/app_storage.html">Manage Data</a> i
n Chrome app docs</p> |
| 8 |
| 9 <h2 id="save_your_todos_in_the_cloud">Save your Todos in the cloud</h2> |
| 10 |
| 11 <p class="note"><b>Note:</b> Chrome Sync Storage is not intended to be used as
a generic database. There are several restrictions on the amount of information
you can save, so it is more appropriate to save settings and other small chunks
of data. </p> |
| 12 |
| 13 <ol> |
| 14 <li><p>Request permission to use storage in your <a href="https://github.com/Goo
gleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/1_storage_sync/mani
fest.json">manifest.json</a>: |
| 15 <pre> |
| 16 { |
| 17 ... , |
| 18 "permissions": ["storage"] |
| 19 } |
| 20 </pre></p></li> |
| 21 <li><p>Change your <a href="https://github.com/GoogleChrome/chrome-app-codelab/b
lob/master/lab5_data/angularjs/1_storage_sync/controller.js">controller.js</a> a
nd, instead of a static list, get the Todo list from the syncable storage: |
| 22 <pre> |
| 23 // Notice that chrome.storage.sync.get is asynchronous |
| 24 chrome.storage.sync.get('todolist', function(value) { |
| 25 // The $apply is only necessary to execute the function inside Angular scope |
| 26 $scope.$apply(function() { |
| 27 $scope.load(value); |
| 28 }); |
| 29 }); |
| 30 |
| 31 // If there is saved data in storage, use it. Otherwise, bootstrap with sample t
odos |
| 32 $scope.load = function(value) { |
| 33 if (value && value.todolist) { |
| 34 $scope.todos = value.todolist; |
| 35 } else { |
| 36 $scope.todos = [ |
| 37 {text:'learn angular', done:true}, |
| 38 {text:'build an angular app', done:false}]; |
| 39 } |
| 40 } |
| 41 |
| 42 $scope.save = function() { |
| 43 chrome.storage.sync.set({'todolist': $scope.todos}); |
| 44 }; |
| 45 </pre></li><li>In the HTML, call <code>save()</code> whenever the data changes.
There are many other ways of doing this in Angular, like using <code>$watchers</
code> on the scope. The one used here makes the <code>save()</code> calls explic
it. |
| 46 <pre> |
| 47 ... |
| 48 [ <a href="" ng-click="archive() || save()">arc
hive</a> ] |
| 49 ... |
| 50 <input type="checkbox" ng-model="todo.done" n
g-change="save()"> |
| 51 ... |
| 52 <form ng-submit="addTodo() || save()"> |
| 53 ... |
| 54 </pre></li> |
| 55 <li>Check the results by reloading the app: open the app, right-click and select
Reload App. |
| 56 You can now add Todo items, close the app, and the new items will still be there
when you reopen the app.</li> |
| 57 </ol> |
| 58 |
| 59 <p class="note"><b>Note:</b> If you get stuck and want to see the app in action
, |
| 60 go to <code>chrome://extensions</code>, load the unpacked <a href="https://githu
b.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/angularjs/1_storage_
sync">1_storage_sync</a> app, |
| 61 and launch the app from a new tab.</p> |
| 62 |
| 63 <h2 id="handle_drag_and_dropped_files_and_urls">Handle drag-and-dropped files an
d URLs</h2> |
| 64 |
| 65 Suppose you want to create Todos associated with local files and/or URLs. The na
tural way of doing this is to accept dropped items. It's simple enough to ad
d drag-and-drop support in a Chrome app using the standard HTML5 Drag-and-Drop A
PI. |
| 66 |
| 67 <ol> |
| 68 <li>In <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/l
ab5_data/angularjs/2_drop_files/controller.js">controller.js</a>, add code to ha
ndle the events of dragover, dragleave and drop: |
| 69 <pre> |
| 70 var defaultDropText = "Or drop files here..."; |
| 71 $scope.dropText = defaultDropText; |
| 72 |
| 73 // on dragOver, we will change the style and text accordingly, depending on |
| 74 // the data being transferred |
| 75 var dragOver = function(e) { |
| 76 e.stopPropagation(); |
| 77 e.preventDefault(); |
| 78 var valid = e.dataTransfer && e.dataTransfer.types |
| 79 && ( e.dataTransfer.types.indexOf('Files') >= 0 |
| 80 || e.dataTransfer.types.indexOf('text/uri-list') >=0 ) |
| 81 $scope.$apply(function() { |
| 82 $scope.dropText = valid ? "Drop files and remote images and they will b
ecome Todos" |
| 83 : "Can only drop files and remote images here"; |
| 84 $scope.dropClass = valid ? "dragging" : "invalid-dragging&quo
t;; |
| 85 }); |
| 86 } |
| 87 |
| 88 // reset style and text to the default |
| 89 var dragLeave = function(e) { |
| 90 $scope.$apply(function() { |
| 91 $scope.dropText = defaultDropText; |
| 92 $scope.dropClass = ''; |
| 93 }); |
| 94 } |
| 95 |
| 96 // on drop, we create the appropriate TODOs using dropped data |
| 97 var drop = function(e) { |
| 98 e.preventDefault(); |
| 99 e.stopPropagation(); |
| 100 |
| 101 var newTodos=[]; |
| 102 if (e.dataTransfer.types.indexOf('Files') >= 0) { |
| 103 var files = e.dataTransfer.files; |
| 104 for (var i = 0; i < files.length; i++) { |
| 105 var text = files[i].name+', '+files[i].size+' bytes'; |
| 106 newTodos.push({text:text, done:false, file: files[i]}); |
| 107 } |
| 108 } else { // uris |
| 109 var uri=e.dataTransfer.getData("text/uri-list"); |
| 110 newTodos.push({text:uri, done:false, uri: uri}); |
| 111 } |
| 112 |
| 113 $scope.$apply(function() { |
| 114 $scope.dropText = defaultDropText; |
| 115 $scope.dropClass = ''; |
| 116 for (var i = 0; i < newTodos.length; i++) { |
| 117 $scope.todos.push(newTodos[i]); |
| 118 } |
| 119 $scope.save(); |
| 120 }); |
| 121 } |
| 122 |
| 123 document.body.addEventListener("dragover", dragOver, false); |
| 124 document.body.addEventListener("dragleave", dragLeave, false); |
| 125 document.body.addEventListener("drop", drop, false); |
| 126 </pre></li><li>To make all the area of the window accept the drop event and stil
l work on the same scope, let's move the Angular scope definition from the d
iv to the body in the <a href="https://github.com/GoogleChrome/chrome-app-codela
b/blob/master/lab5_data/angularjs/2_drop_files/index.html">index.html</a> file. |
| 127 Also, let's associate the body's CSS class with the Angular controller&#
39;s class, so we can change the class directly in the scope and have it automat
ically changed in the DOM: |
| 128 <pre> |
| 129 <body ng-controller="TodoCtrl" ng-class="dropClass"> |
| 130 <!-- remember to remove the ng-controller attribute from the div where it was
before --> |
| 131 </pre></li> |
| 132 <li>Add a message placeholder (in <code>index.html</code>) to warn the user that
some types of dragging are not allowed: |
| 133 <pre> |
| 134 <div> |
| 135 {{dropText}} |
| 136 </div> |
| 137 </pre></li> |
| 138 <li>Add appropriate styling for the <code>dragging</code> and <code>invalid-drag
ging</code> CSS classes in <a href="https://github.com/GoogleChrome/chrome-app-c
odelab/blob/master/lab5_data/angularjs/2_drop_files/todo.css">todo.css</a>. Here
we used a green or red background color animation: |
| 139 <pre> |
| 140 @-webkit-keyframes switch-green { |
| 141 from { background-color: white;} to {background-color: rgb(163, 255, 163);} |
| 142 } |
| 143 @-webkit-keyframes switch-red { |
| 144 from { background-color: white;} to {background-color: rgb(255, 203, 203);} |
| 145 } |
| 146 .dragging { |
| 147 -webkit-animation: switch-green 0.5s ease-in-out 0 infinite alternate; |
| 148 } |
| 149 |
| 150 .invalid-dragging { |
| 151 -webkit-animation: switch-red 0.5s ease-in-out 0 infinite alternate; |
| 152 } |
| 153 </pre></p></li><li><p>Check the results by reloading the app: open the app, righ
t-click and select Reload App. |
| 154 You can now drag files into the Todo list.</p></li> |
| 155 </ol> |
| 156 |
| 157 <p class="note"><b>Note:</b> If you get stuck and want to see the app in action
, |
| 158 go to <code>chrome://extensions</code>, load the unpacked <a href="https://githu
b.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/angularjs/2_drop_fil
es">2_drop_files</a> app, |
| 159 and launch the app from a new tab.</p> |
| 160 |
| 161 <h1 id="challenge_">Challenge:</h1> |
| 162 |
| 163 <p>The current code only saves the file reference, but it doesn't open the f
ile. Using the <a href="http://www.html5rocks.com/en/tutorials/file/filesystem/"
>HTML5 Filesystem API</a>, save the file contents in a sandboxed filesystem. Whe
n the Todo item is archived, remove the corresponding file from the sandboxed fi
lesystem. Add an "open" link on each Todo that has an associated file.
When the item is clicked and the file exists in the sandboxed filesystem, use t
he Chrome app <a href="http://developer.chrome.com/apps/fileSystem.html">Filesys
tem extension</a> to request a writable FileEntry from the user. Save the file d
ata from the sandboxed filesystem into that entry.</p> |
| 164 |
| 165 <p class="note"><b>Tip:</b> managing file entries using the raw HTML5 Filesyste
m API is not trivial. You might want to use a wrapper library, like Eric Bidelma
n's <a href="https://github.com/ebidel/filer.js">filer.js</a>.</p> |
| 166 |
| 167 <h1 id="takeaways_">Takeaways:</h1> |
| 168 |
| 169 <ul> |
| 170 <li><p>Use <a href="http://developer.chrome.com/apps/storage.html">chrome.storag
e.sync</a> to save small data that you need to be sync'ed among devices, lik
e configuration options, application state, etc. The sync is automatic, as long
as the same user is logged into Chrome on all devices.</p></li> |
| 171 <li><p>Chrome apps support almost all HTML5 APIs, such as drag and drop. HTML Fi
lesystem API is also supported, with extra features from the Chrome app's <a
href="http://developer.chrome.com/apps/fileSystem.html">Filesystem API extensio
n</a>, like asking the user to pick files on her local disk for read and write.
The vanilla HTML5 Filesystem API only allows access to a sandboxed filesystem.</
p></li> |
| 172 </ul> |
| 173 |
| 174 <h1 id="what_39_s_next_">What's next?</h1> |
| 175 |
| 176 <p>In <a href="app_codelab6_lifecycle.html">lab6_lifecycle</a>, you will learn t
he basics of the Chrome app lifecycle. </p> |
OLD | NEW |