| OLD | NEW |
| 1 <meta name="doc-family" content="apps"> | 1 <meta name="doc-family" content="apps"> |
| 2 <h1>Build Apps with AngularJS</h1> | 2 <h1>Build Apps with AngularJS</h1> |
| 3 <!--Article written by Eric Bidelman--> | 3 <!--Article written by Eric Bidelman--> |
| 4 <p> | 4 <p> |
| 5 This guide gets you started building Chrome Apps | 5 This guide gets you started building Chrome Apps |
| 6 with the <a href="http://angularjs.org/">AngularJS</a> MVC framework. | 6 with the <a href="http://angularjs.org/">AngularJS</a> MVC framework. |
| 7 To illustrate Angular in action, | 7 To illustrate Angular in action, |
| 8 we'll be referencing an actual app built using the framework, | 8 we'll be referencing an actual app built using the framework, |
| 9 the Google Drive Uploader. | 9 the Google Drive Uploader. |
| 10 The <a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/gdri
ve">source code</a> | 10 The <a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/gdri
ve">source code</a> |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 <a href="http://www.html5rocks.com/en/tutorials/dnd/basics/">HTML Drag and Drop
APIs</a>. | 26 <a href="http://www.html5rocks.com/en/tutorials/dnd/basics/">HTML Drag and Drop
APIs</a>. |
| 27 It's a great example of building an app which talks | 27 It's a great example of building an app which talks |
| 28 to one of <a href="https://developers.google.com/apis-explorer/#p/">Google's API
s</a>; | 28 to one of <a href="https://developers.google.com/apis-explorer/#p/">Google's API
s</a>; |
| 29 in this case, the Google Drive API. | 29 in this case, the Google Drive API. |
| 30 </p> | 30 </p> |
| 31 | 31 |
| 32 <p class="note"> | 32 <p class="note"> |
| 33 <strong>Note: </strong> | 33 <strong>Note: </strong> |
| 34 You can also build apps which talk to 3rd party APIs/services | 34 You can also build apps which talk to 3rd party APIs/services |
| 35 that are OAuth2-enabled. | 35 that are OAuth2-enabled. |
| 36 See <a href="app_identity.html#non">non-Google Account authentication</a>. | 36 See <a href="app_identity#non">non-Google Account authentication</a>. |
| 37 </p> | 37 </p> |
| 38 | 38 |
| 39 <p> | 39 <p> |
| 40 The Uploader uses OAuth2 to access the user's data. The | 40 The Uploader uses OAuth2 to access the user's data. The |
| 41 <a href="identity.html">chrome.identity API</a> | 41 <a href="identity">chrome.identity API</a> |
| 42 handles fetching an OAuth token for the logged-in user, | 42 handles fetching an OAuth token for the logged-in user, |
| 43 so the hard work is done for us! | 43 so the hard work is done for us! |
| 44 Once we have a long-lived access token, | 44 Once we have a long-lived access token, |
| 45 the apps uses the | 45 the apps uses the |
| 46 <a href="https://developers.google.com/drive/get-started">Google Drive API</a> | 46 <a href="https://developers.google.com/drive/get-started">Google Drive API</a> |
| 47 to access the user's data. | 47 to access the user's data. |
| 48 </p> | 48 </p> |
| 49 | 49 |
| 50 <p> | 50 <p> |
| 51 Key features this app uses: | 51 Key features this app uses: |
| 52 </p> | 52 </p> |
| 53 | 53 |
| 54 <ul> | 54 <ul> |
| 55 <li>AngularJS's autodetection for | 55 <li>AngularJS's autodetection for |
| 56 <a href="contentSecurityPolicy.html">CSP</a></li> | 56 <a href="contentSecurityPolicy">CSP</a></li> |
| 57 <li>Render a list of files fetched from the | 57 <li>Render a list of files fetched from the |
| 58 <a href="https://developers.google.com/drive/get-started">Google Drive A
PI</a></li> | 58 <a href="https://developers.google.com/drive/get-started">Google Drive A
PI</a></li> |
| 59 <li><a href="http://www.html5rocks.com/en/tutorials/file/filesystem/">HTML5
Filesystem API</a> | 59 <li><a href="http://www.html5rocks.com/en/tutorials/file/filesystem/">HTML5
Filesystem API</a> |
| 60 to store file icons offline</li> | 60 to store file icons offline</li> |
| 61 <li><a href="http://www.html5rocks.com/en/tutorials/dnd/basics/">HTML5 Drag
and Drop</a> | 61 <li><a href="http://www.html5rocks.com/en/tutorials/dnd/basics/">HTML5 Drag
and Drop</a> |
| 62 for importing/uploading new files from the desktop</li> | 62 for importing/uploading new files from the desktop</li> |
| 63 <li>XHR2 to load images, cross-domain</li> | 63 <li>XHR2 to load images, cross-domain</li> |
| 64 <li><a href="app_identity.html">chrome.identity API</a> | 64 <li><a href="app_identity">chrome.identity API</a> |
| 65 for OAuth authorization</li> | 65 for OAuth authorization</li> |
| 66 <li>Chromeless frames to define the app's own navbar look and feel</li> | 66 <li>Chromeless frames to define the app's own navbar look and feel</li> |
| 67 </ul> | 67 </ul> |
| 68 | 68 |
| 69 <h2 id="second">Creating the manifest</h2> | 69 <h2 id="second">Creating the manifest</h2> |
| 70 | 70 |
| 71 <p> | 71 <p> |
| 72 All Chrome Apps require a <code>manifest.json</code> file | 72 All Chrome Apps require a <code>manifest.json</code> file |
| 73 which contains the information Chrome needs to launch the app. | 73 which contains the information Chrome needs to launch the app. |
| 74 The manifest contains relevant metadata and | 74 The manifest contains relevant metadata and |
| (...skipping 26 matching lines...) Expand all Loading... |
| 101 } | 101 } |
| 102 </pre> | 102 </pre> |
| 103 | 103 |
| 104 <p> | 104 <p> |
| 105 The most important parts of this manifest are the "oauth2" and "permissions" sec
tions. | 105 The most important parts of this manifest are the "oauth2" and "permissions" sec
tions. |
| 106 </p> | 106 </p> |
| 107 | 107 |
| 108 <p> | 108 <p> |
| 109 The "oauth2" section defines the required parameters by OAuth2 to do its magic. | 109 The "oauth2" section defines the required parameters by OAuth2 to do its magic. |
| 110 To create a "client_id", follow the instructions in | 110 To create a "client_id", follow the instructions in |
| 111 <a href="app_identity.html#client_id">Get your client id</a>. | 111 <a href="app_identity#client_id">Get your client id</a>. |
| 112 The "scopes" list the authorization scopes | 112 The "scopes" list the authorization scopes |
| 113 that the OAuth token will be valid for (for example, the APIs the app wants to a
ccess). | 113 that the OAuth token will be valid for (for example, the APIs the app wants to a
ccess). |
| 114 </p> | 114 </p> |
| 115 | 115 |
| 116 <p> | 116 <p> |
| 117 The "permissions" section includes URLs that the app will access via XHR2. | 117 The "permissions" section includes URLs that the app will access via XHR2. |
| 118 The URL prefixes are required in order for Chrome | 118 The URL prefixes are required in order for Chrome |
| 119 to know which cross-domain requests to allow. | 119 to know which cross-domain requests to allow. |
| 120 </p> | 120 </p> |
| 121 | 121 |
| 122 <h2 id="three">Creating the event page</h2> | 122 <h2 id="three">Creating the event page</h2> |
| 123 | 123 |
| 124 <p> | 124 <p> |
| 125 All Chrome Apps require a background script/page | 125 All Chrome Apps require a background script/page |
| 126 to launch the app and respond to system events. | 126 to launch the app and respond to system events. |
| 127 </p> | 127 </p> |
| 128 | 128 |
| 129 <p> | 129 <p> |
| 130 In its | 130 In its |
| 131 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/j
s/background.js">background.js</a> | 131 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/j
s/background.js">background.js</a> |
| 132 script, | 132 script, |
| 133 Drive Uploader opens a 500x600px window to the main page. | 133 Drive Uploader opens a 500x600px window to the main page. |
| 134 It also specifies a minimum height and width for the window | 134 It also specifies a minimum height and width for the window |
| 135 so the content doesn't become too crunched: | 135 so the content doesn't become too crunched: |
| 136 </p> | 136 </p> |
| 137 | 137 |
| 138 <pre data-filename="background.js"> | 138 <pre data-filename="background.js"> |
| 139 chrome.app.runtime.onLaunched.addListener(function(launchData) { | 139 chrome.app.runtime.onLaunched.addListener(function(launchData) { |
| 140 chrome.app.window.create('../main.html', { | 140 chrome.app.window.create('../main', { |
| 141 id: "GDriveExample", | 141 id: "GDriveExample", |
| 142 bounds: { | 142 bounds: { |
| 143 width: 500, | 143 width: 500, |
| 144 height: 600 | 144 height: 600 |
| 145 }, | 145 }, |
| 146 minWidth: 500, | 146 minWidth: 500, |
| 147 minHeight: 600, | 147 minHeight: 600, |
| 148 frame: 'none' | 148 frame: 'none' |
| 149 }); | 149 }); |
| 150 }); | 150 }); |
| 151 </pre> | 151 </pre> |
| 152 | 152 |
| 153 <p> | 153 <p> |
| 154 The window is created as a chromeless window (frame: 'none'). | 154 The window is created as a chromeless window (frame: 'none'). |
| 155 By default, windows render with the OS's default close/expand/minimize bar: | 155 By default, windows render with the OS's default close/expand/minimize bar: |
| 156 </p> | 156 </p> |
| 157 | 157 |
| 158 <img src="{{static}}/images/noframe.png" | 158 <img src="{{static}}/images/noframe.png" |
| 159 width="508" | 159 width="508" |
| 160 height="75" | 160 height="75" |
| 161 alt="Google Drive Uploader with no frame"> | 161 alt="Google Drive Uploader with no frame"> |
| 162 | 162 |
| 163 <p> | 163 <p> |
| 164 The Uploader uses <code>frame: 'none'</code> to render the window as a "blank sl
ate" | 164 The Uploader uses <code>frame: 'none'</code> to render the window as a "blank sl
ate" |
| 165 and creates a custom close button in <code>main.html</code>: | 165 and creates a custom close button in <code>main</code>: |
| 166 </p> | 166 </p> |
| 167 | 167 |
| 168 <img src="{{static}}/images/customframe.png" | 168 <img src="{{static}}/images/customframe.png" |
| 169 width="504" | 169 width="504" |
| 170 height="50" | 170 height="50" |
| 171 alt="Google Drive Uploader with custom frame"> | 171 alt="Google Drive Uploader with custom frame"> |
| 172 | 172 |
| 173 <p> | 173 <p> |
| 174 The entire navigational area is wrapped in a <nav> (see next section). | 174 The entire navigational area is wrapped in a <nav> (see next section). |
| 175 To declutter the app a bit, | 175 To declutter the app a bit, |
| 176 the custom close button is hidden until the user interacts with this the area: | 176 the custom close button is hidden until the user interacts with this the area: |
| 177 </p> | 177 </p> |
| 178 | 178 |
| 179 <pre data-filename="main.css"> | 179 <pre data-filename="main.css"> |
| 180 <style> | 180 <style> |
| 181 nav:hover #close-button { | 181 nav:hover #close-button { |
| 182 opacity: 1; | 182 opacity: 1; |
| 183 } | 183 } |
| 184 | 184 |
| 185 #close-button { | 185 #close-button { |
| 186 float: right; | 186 float: right; |
| 187 padding: 0 5px 2px 5px; | 187 padding: 0 5px 2px 5px; |
| 188 font-weight: bold; | 188 font-weight: bold; |
| 189 opacity: 0; | 189 opacity: 0; |
| 190 -webkit-transition: all 0.3s ease-in-out; | 190 -webkit-transition: all 0.3s ease-in-out; |
| 191 } | 191 } |
| 192 </style> | 192 </style> |
| 193 </pre> | 193 </pre> |
| 194 <pre data-filename="main.html"> | 194 <pre data-filename="main"> |
| 195 <button class="btn" id="close-button" title="Close">x</button> | 195 <button class="btn" id="close-button" title="Close">x</button> |
| 196 </pre> | 196 </pre> |
| 197 | 197 |
| 198 <p> | 198 <p> |
| 199 In | 199 In |
| 200 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/j
s/app.js">app.js</a>, | 200 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/j
s/app.js">app.js</a>, |
| 201 this button is hooked up to <code>window.close()</code>. | 201 this button is hooked up to <code>window.close()</code>. |
| 202 </p> | 202 </p> |
| 203 | 203 |
| 204 <h2 id="four">Designing the app the Angular way</h2> | 204 <h2 id="four">Designing the app the Angular way</h2> |
| 205 | 205 |
| 206 <p> | 206 <p> |
| 207 Angular is an MVC framework, so we need to define the app in such a way that a | 207 Angular is an MVC framework, so we need to define the app in such a way that a |
| 208 model, view, and controller logically fall out of it. Luckily, this is trivial w
hen using Angular. | 208 model, view, and controller logically fall out of it. Luckily, this is trivial w
hen using Angular. |
| 209 </p> | 209 </p> |
| 210 | 210 |
| 211 <p> | 211 <p> |
| 212 The View is the easiest, so let's start there. | 212 The View is the easiest, so let's start there. |
| 213 </p> | 213 </p> |
| 214 | 214 |
| 215 <h3 id="view">Creating the view</h3> | 215 <h3 id="view">Creating the view</h3> |
| 216 | 216 |
| 217 <p> | 217 <p> |
| 218 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/m
ain.html">main.html</a> | 218 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/m
ain">main</a> |
| 219 is the "V" in MVC; where we define HTML templates to render data into. | 219 is the "V" in MVC; where we define HTML templates to render data into. |
| 220 In Angular, templates are simple blocks of HTML with some special sauce. | 220 In Angular, templates are simple blocks of HTML with some special sauce. |
| 221 </p> | 221 </p> |
| 222 | 222 |
| 223 <p> | 223 <p> |
| 224 Ultimately we want to display the user's list of files. | 224 Ultimately we want to display the user's list of files. |
| 225 For that, a simple <ul> list makes sense. | 225 For that, a simple <ul> list makes sense. |
| 226 The Angular bits are highlighted in bold: | 226 The Angular bits are highlighted in bold: |
| 227 </p> | 227 </p> |
| 228 | 228 |
| 229 <pre data-filename="main.html"> | 229 <pre data-filename="main"> |
| 230 <ul> | 230 <ul> |
| 231 <li <strong>data-ng-repeat="doc in docs"</strong>> | 231 <li <strong>data-ng-repeat="doc in docs"</strong>> |
| 232 <img data-ng-src=<strong>"{{doc.icon}}"</strong>> <a href=<s
trong>"{{doc.alternateLink}}"</strong>><strong>{{doc.title}}
</strong></a> | 232 <img data-ng-src=<strong>"{{doc.icon}}"</strong>> <a href=<s
trong>"{{doc.alternateLink}}"</strong>><strong>{{doc.title}}
</strong></a> |
| 233 <strong>{{doc.size}}</strong> | 233 <strong>{{doc.size}}</strong> |
| 234 <span class="date"><strong>{{doc.updatedDate}}</strong></spa
n> | 234 <span class="date"><strong>{{doc.updatedDate}}</strong></spa
n> |
| 235 </li> | 235 </li> |
| 236 </ul> | 236 </ul> |
| 237 </pre> | 237 </pre> |
| 238 | 238 |
| 239 <p> | 239 <p> |
| (...skipping 12 matching lines...) Expand all Loading... |
| 252 You could easily write the repeater as <code><li ng-repeat="doc in docs"></co
de>. | 252 You could easily write the repeater as <code><li ng-repeat="doc in docs"></co
de>. |
| 253 </p> | 253 </p> |
| 254 | 254 |
| 255 <p> | 255 <p> |
| 256 Next, we need to tell Angular which controller will oversee this template's rend
ering. | 256 Next, we need to tell Angular which controller will oversee this template's rend
ering. |
| 257 For that, we use the | 257 For that, we use the |
| 258 <a href="http://docs.angularjs.org/api/ng.directive:ngController">ngController</
a> | 258 <a href="http://docs.angularjs.org/api/ng.directive:ngController">ngController</
a> |
| 259 directive to tell the <code>DocsController</code> to have reign over the templat
e <body>: | 259 directive to tell the <code>DocsController</code> to have reign over the templat
e <body>: |
| 260 </p> | 260 </p> |
| 261 | 261 |
| 262 <pre data-filename="main.html"> | 262 <pre data-filename="main"> |
| 263 <body <strong>data-ng-controller="DocsController"</strong>> | 263 <body <strong>data-ng-controller="DocsController"</strong>> |
| 264 <section id="main"> | 264 <section id="main"> |
| 265 <ul> | 265 <ul> |
| 266 <li data-ng-repeat="doc in docs"> | 266 <li data-ng-repeat="doc in docs"> |
| 267 <img data-ng-src="{{doc.icon}}"> <a href="{{doc.alter
nateLink}}">{{doc.title}}</a> {{doc.size}} | 267 <img data-ng-src="{{doc.icon}}"> <a href="{{doc.alter
nateLink}}">{{doc.title}}</a> {{doc.size}} |
| 268 <span class="date">{{doc.updatedDate}}</span> | 268 <span class="date">{{doc.updatedDate}}</span> |
| 269 </li> | 269 </li> |
| 270 </ul> | 270 </ul> |
| 271 </section> | 271 </section> |
| 272 </body> | 272 </body> |
| 273 </pre> | 273 </pre> |
| 274 | 274 |
| 275 <p> | 275 <p> |
| 276 Keep in mind, | 276 Keep in mind, |
| 277 what you don't see here is us hooking up event listeners or properties for data
binding. | 277 what you don't see here is us hooking up event listeners or properties for data
binding. |
| 278 Angular is doing that heavy lifting for us! | 278 Angular is doing that heavy lifting for us! |
| 279 </p> | 279 </p> |
| 280 | 280 |
| 281 <p> | 281 <p> |
| 282 The last step is to make Angular light up our templates. | 282 The last step is to make Angular light up our templates. |
| 283 The typical way to do that is include the | 283 The typical way to do that is include the |
| 284 <a href="http://docs.angularjs.org/api/ng.directive:ngApp">ngApp</a> | 284 <a href="http://docs.angularjs.org/api/ng.directive:ngApp">ngApp</a> |
| 285 directive all the way up on <html>: | 285 directive all the way up on <html>: |
| 286 </p> | 286 </p> |
| 287 | 287 |
| 288 <pre data-filename="main.html"> | 288 <pre data-filename="main"> |
| 289 <html <strong>data-ng-app="gDriveApp"</strong>> | 289 <html <strong>data-ng-app="gDriveApp"</strong>> |
| 290 </pre> | 290 </pre> |
| 291 | 291 |
| 292 <p> | 292 <p> |
| 293 You could also scope the app down | 293 You could also scope the app down |
| 294 to a smaller portion of the page if you wanted to. | 294 to a smaller portion of the page if you wanted to. |
| 295 We only have one controller in this app, | 295 We only have one controller in this app, |
| 296 but if we were to add more later, | 296 but if we were to add more later, |
| 297 putting <a href="http://docs.angularjs.org/api/ng.directive:ngApp">ngApp</a> | 297 putting <a href="http://docs.angularjs.org/api/ng.directive:ngApp">ngApp</a> |
| 298 on the topmost element makes the entire page Angular-ready. | 298 on the topmost element makes the entire page Angular-ready. |
| 299 </p> | 299 </p> |
| 300 | 300 |
| 301 <p> | 301 <p> |
| 302 The final product for <code>main.html</code> looks something like this: | 302 The final product for <code>main</code> looks something like this: |
| 303 </p> | 303 </p> |
| 304 | 304 |
| 305 <pre data-filename="main.html"> | 305 <pre data-filename="main"> |
| 306 <html <strong>data-ng-app="gDriveApp"</strong>> | 306 <html <strong>data-ng-app="gDriveApp"</strong>> |
| 307 <head> | 307 <head> |
| 308 … | 308 … |
| 309 <!-- crbug.com/120693: so we don't need target="_blank" on every anchor. --> | 309 <!-- crbug.com/120693: so we don't need target="_blank" on every anchor. --> |
| 310 <base target="_blank"> | 310 <base target="_blank"> |
| 311 </head> | 311 </head> |
| 312 <body <strong>data-ng-controller="DocsController"</strong>> | 312 <body <strong>data-ng-controller="DocsController"</strong>> |
| 313 <section id="main"> | 313 <section id="main"> |
| 314 <nav> | 314 <nav> |
| 315 <h2>Google Drive Uploader</h2> | 315 <h2>Google Drive Uploader</h2> |
| 316 <button class="btn" <strong>data-ng-click="fetchDocs()"</strong>>Refresh&
lt;/button> | 316 <button class="btn" <strong>data-ng-click="fetchDocs()"</strong>>Refresh&
lt;/button> |
| 317 <button class="btn" id="close-button" title="Close"></button> | 317 <button class="btn" id="close-button" title="Close"></button> |
| 318 </nav> | 318 </nav> |
| 319 <ul> | 319 <ul> |
| 320 <li <strong>data-ng-repeat="doc in docs"</strong>> | 320 <li <strong>data-ng-repeat="doc in docs"</strong>> |
| 321 <img data-ng-src=<strong>"{{doc.icon}}"</strong>> <a href=
<strong>"{{doc.alternateLink}}"</strong>><strong>{{doc.title}
5;</strong></a> <strong>{{doc.size}}</strong> | 321 <img data-ng-src=<strong>"{{doc.icon}}"</strong>> <a href=
<strong>"{{doc.alternateLink}}"</strong>><strong>{{doc.title}
5;</strong></a> <strong>{{doc.size}}</strong> |
| 322 <span class="date"><strong>{{doc.updatedDate}}</strong></s
pan> | 322 <span class="date"><strong>{{doc.updatedDate}}</strong></s
pan> |
| 323 </li> | 323 </li> |
| 324 </ul> | 324 </ul> |
| 325 </section> | 325 </section> |
| 326 </pre> | 326 </pre> |
| 327 | 327 |
| 328 <h3 id="csp">A word on Content Security Policy</h3> | 328 <h3 id="csp">A word on Content Security Policy</h3> |
| 329 | 329 |
| 330 <p> | 330 <p> |
| 331 Unlike many other JS MVC frameworks, | 331 Unlike many other JS MVC frameworks, |
| 332 Angular v1.1.0+ requires no tweaks to work within a strict | 332 Angular v1.1.0+ requires no tweaks to work within a strict |
| 333 <a href="contentSecurityPolicy.html">CSP</a>. | 333 <a href="contentSecurityPolicy">CSP</a>. |
| 334 It just works, out of the box! | 334 It just works, out of the box! |
| 335 </p> | 335 </p> |
| 336 | 336 |
| 337 <p> | 337 <p> |
| 338 However, if you're using an older version | 338 However, if you're using an older version |
| 339 of Angular between v1.0.1 and v1.1.0, | 339 of Angular between v1.0.1 and v1.1.0, |
| 340 you'll need tell Angular to run in a "content security mode". | 340 you'll need tell Angular to run in a "content security mode". |
| 341 This is done by including the | 341 This is done by including the |
| 342 <a href="http://docs.angularjs.org/api/ng.directive:ngCsp">ngCsp</a> | 342 <a href="http://docs.angularjs.org/api/ng.directive:ngCsp">ngCsp</a> |
| 343 directive alongside <a href="http://docs.angularjs.org/api/ng.directive:ngApp">n
gApp</a>: | 343 directive alongside <a href="http://docs.angularjs.org/api/ng.directive:ngApp">n
gApp</a>: |
| 344 </p> | 344 </p> |
| 345 | 345 |
| 346 <pre data-filename="main.html"> | 346 <pre data-filename="main"> |
| 347 <html data-ng-app data-ng-csp> | 347 <html data-ng-app data-ng-csp> |
| 348 </pre> | 348 </pre> |
| 349 | 349 |
| 350 <h3 id="authorization">Handling authorization</h3> | 350 <h3 id="authorization">Handling authorization</h3> |
| 351 | 351 |
| 352 <p> | 352 <p> |
| 353 The data model isn't generated by the app itself. | 353 The data model isn't generated by the app itself. |
| 354 Instead, it's populated from an external API (the Google Drive API). | 354 Instead, it's populated from an external API (the Google Drive API). |
| 355 Thus, there's a bit of work necessary in order to populate the app's data. | 355 Thus, there's a bit of work necessary in order to populate the app's data. |
| 356 </p> | 356 </p> |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 750 $scope.fetchDocs(); | 750 $scope.fetchDocs(); |
| 751 }); | 751 }); |
| 752 }); | 752 }); |
| 753 }); | 753 }); |
| 754 | 754 |
| 755 return gdocs; | 755 return gdocs; |
| 756 }); | 756 }); |
| 757 </pre> | 757 </pre> |
| 758 | 758 |
| 759 <p class="backtotop"><a href="#top">Back to top</a></p> | 759 <p class="backtotop"><a href="#top">Back to top</a></p> |
| OLD | NEW |