Chrome Apps Office Hours: TextDrive and AngularJS

Uploaded by GoogleDevelopers on 11.09.2012


BILL LUAN: Shanghai GDG is a very
interesting developer community.
SUSANNAH RAUB: I'm glad somebody
has asked this question.
RETO MEIER: This is where the magic happens.
JENNY MURPHY: This is primarily a question and
answer show.
So if any of you out there would like to ask questions.

PETE LEPAGE: Welcome, everybody.
This is, I think, our fourth or fifth in the installment of
the Chrome Apps Office Hours.
This week, we have a really cool event with some special
guests who are joining us.
This is the AngularJS team, who was one of the first teams
here at Google to build a Chrome app using, obviously,
the AngularJS framework.
And they've learned a lot over the last couple of months on
how to build these things, some of the issues they've run
into, as well as how to get around those.
And really, how to build a really cool Chrome app.
So I'd like to introduce Brad Green and Vojta--
I forgot your last name.
I apologize.
Vojta, I think that's enough.
PETE LEPAGE: All right.
Brad, Vojta, why don't you guys introduce yourselves.
And we can talk about TextDrive, this
app that you guys--
So yeah, I'm Brad Green.
I manage the AngularJS project here at Google.
And Vojta is one of the engineers on the project.
And we built this app, TextDrive.
It's a simple text editor.
And it allows you to edit text, which is actually cooler
than you think on Chrome.
Because if you want to edit your CRX file without having
to go rebuild the bundle, this is a really cool thing to do.
But I think it's a really good example of
pulling some pieces together.
Some of these V2 APIs.
We're showing you how you can take really good advantage of
them with Angular.
So without talking too much more, Vojta, why don't you
take us through the app itself.
VOJTA JINA: Oh, sure.
As we said, it's just a text editor.
So you can open files, you can create new files--
PETE LEPAGE: Now, I just want to interject here for one sec.
You can open files anywhere on your file system, right?
This is not just a matter of hey, you're limited to the
normal file system.
No, this is my file system.
BRAD GREEN: And just to mention, we're using a MacBook
here, but this works on my Chromebook as well.
PETE LEPAGE: Absolutely, yeah.
So I can create new files.
I think a really cool feature is the searching.
So the first thing, you can just search.
I can search for ng-click or something.
But, more than that, if you start searching with forward
slash, it does this like grip-like filtering.
So I can say ng-controller, for instance.
And you can see how it filters just the lines that matches
this regular expression.
And I can go edit the text, or--
BRAD GREEN: So it collapses all the code.
VOJTA JINA: Yeah, it just collapsed it, so I can--

PETE LEPAGE: And it's not just text.
But you've also got some things in there so that
editing code becomes that much easier as well.
I think the main purpose of this thing is for editing any
sort of source code.
BRAD GREEN: So just a little bit more of
how we put this together.
So we're using the ACE editor component.
VOJTA JINA: Which is awesome.
BRAD GREEN: It is fantastic.
But that doesn't make a full app.
So as the wiring bit, we're using Angular to pull the
whole thing together into an app.
And then we're using these V2 APIs to be able to access all
the pieces we need to make it a real application.

VOJTA JINA: Maybe the last thing I could show is there
are settings, as well.
So you can change the theme--

BRAD GREEN: Fantastic.
If I want to code in the dark.
VOJTA JINA: All these settings are synchronized through
Chrome sync storage.
PETE LEPAGE: So if I'm logged into Chrome on one machine,
and then go to a different machine and start editing
files, I get the same settings--
VOJTA JINA: Hopefully, you will get the same settings.
PETE LEPAGE: Very cool.
So that was something we talked about last week with
the Chrome storage APIs being able to sync those across
multiple machines.

BRAD GREEN: So it's kind of a basic text editor.
I think the interesting part is how this editor works, and
how we built it, and some of the lessons we learned.
VOJTA JINA: Yeah, I think we learned a lot of stuff, even
about Angler to about--
VOJTA JINA: We are developing Angular.
But sometimes it's good to develop something with
Angular, so that you can see--
BRAD GREEN: Absolutely.
VOJTA JINA: I think we learned a lot of lessons as well.
BRAD GREEN: So just for the folks who haven't used Angular
before, let me just give a brief overview.
Angular is a framework for building web apps.
And it really helps you build MVC--
model-view-controller style web apps.
And it does this through a couple mechanisms.
And you can check this out at
We've got a ton of code examples.
We support it through something called data binding,
where we automatically synchronize elements in your
UI, and the state of them, into your properties in your
model, into your JavaScript objects.
We also have something called directives, which allow you to
extend HTML syntax.
So that instead of having a whole bunch of divs and spans,
if you want to build tabs, you can just
say tab, angle bracket.
Or, you can-- if you're not in an HTML5 browser--
you can still say, color picker, angle bracket.
You can make that work in any browser on the web.
And we'll see some of these features, and how they come
together to build a really nice MVC-style app.
So, Vojta, can you take us through some of this?
As a matter of fact, let's look at the app itself.
So in MVC, the controllers usually map to certain
parts of the UI.
And Vojta--
VOJTA JINA: And that's exactly what it does in Angular.
BRAD GREEN: That is what is does in Angular.
Vojta's cooked this up so that's we can actually see
which controllers map to which parts of the UI.
So there is one root controller,
which is called App.
And that's basically responsible for stuff like--
it keeps some state, like the settings, is it
open or is it closed?
Is this search dialogue open, or is it closed?
And stuff like that.
So that's App controller.
Then we have Tabs controller, which is right over
there at the top.
And that is responsible for these buttons over there, in
the right top corner, as well as all the tabs.
So creating new tab, closing tab, focusing tabs.
Basically keeping the state of which tab is selected, and
stuff like that.
Then we have StatusBar controller, which, again, is
responsible for some stuff here.
So for instance, you can manually change the file type,
and stuff like that.
And last piece is Settings controller, at the bottom.
And that's responsible for changing the settings.
VOJTA JINA: I think that's pretty much the overview.
These are the controllers that we use.
Well, let's look at some of the code.
And let's maybe zoom into the Tabs controller.
Would you take us through a little bit of how that works?
Maybe we'll start on the template.
That's a good idea, actually.
So this is index.html, which is basically a template of
this whole app.
It's just one template.
And you can see this header right over there, which is
controlled by Tabs controller.
And the first div--
that's these buttons right over there.
And then we have these tabs, which are done just by CSS.
So it's just unordered list.
BRAD GREEN: This is the template of one tab, that will
get expanded into multiple tabs.
VOJTA JINA: Exactly.
You can see, there is this just one item.
And that's one tab.
And this whole code basically creates one tab.
And here is when Angular comes into play, because it says,
repeat this tab for every tab in tabs.
So I think we might go to tabs controller, which is actually
pretty lightweight.
And most of the stuff is in tab service.
So let me actually go to tab service.
And I think we might show people adding or something.
BRAD GREEN: Yeah, let's look at Add.
I think Add is the interesting part of tabs.
VOJTA JINA: So here is the source code to
actually add a tab.
And I think you can see the magic of two-way
data binding here.
Because what we do, we just create a new
instance of tab object.
And then we basically just push it into an array.
So tabs itself, if I search for this, tabs is just the
JavaScript array.
Nothing special.
So for me, in order to create a new tab, I just push a new
tab into this array.
And this two-way data binding automatically will synchronize
it, so that if I create a new tab--
BRAD GREEN: Because we have it bound to the UI, it knows
that, for every item in the array, I will create this tab
template that you showed off.
PETE LEPAGE: I think one of the things that I've really
liked when I've played with Angular is that there's no
really funky data set up or anything that I need to do.
Those are just an array--
VOJTA JINA: Exactly.
PETE LEPAGE: --of strings, right?
BRAD GREEN: That's right.
PETE LEPAGE: That I can just say, hey--
VOJTA JINA: Just needed the array.
PETE LEPAGE: There you go.
VOJTA JINA: Which makes it really easy to work, for
instance, with some third-party code.
You don't have to wrap it with some custom stuff.
PETE LEPAGE: And it makes it easier, at some point, to
serialize it out, as well.
Because I don't have all this crazy stuff that's in there.
BRAD GREEN: For sure.
All right so do you want to take a look at how we maximize
the window?
Do you want to see that?
VOJTA JINA: Yeah, sure.
So that's an Tabs controller as well.
BRAD GREEN: Let's describe what you're doing here.
Because the maximize window is part of the windowing API,
which means that we've got the ability to be able to
completely change the window and size, minimize, maximize.
VOJTA JINA: I can show you--
PETE LEPAGE: Stuff we can't do with normal web apps today.
BRAD GREEN: That's right.
PETE LEPAGE: But we expect to be able to do with apps that
are installed on our machine.

VOJTA JINA: So this controller just calls something.
We call it Service.
And we have App Windows service.
Let me actually show you this.
So this service is really lightweight.
It's just a tiny wrapper around this Chrome API.
And I think that was one of the lessons that I learned.
The reason for doing this tiny wrapper, which is basically
almost empty service, I think there are two
advantages of that.
First thing is whenever this API changes, you have single
place, where to change it.
And for instance, this API--
BRAD GREEN: The importance of using API.
VOJTA JINA: This API has changed at least four times.
And then it's easy to change it, because
there's just one place.
And you change this single place.
And the rest of the app doesn't care.
So that's the first thing.
And then the second thing is testability.
Because most of those things, like Windows close.
You don't want to do that in unit test.
You don't want to close the window doing unit testing.
So once you have this tiny wrapper, you can just easily
inject different versions during unit testing.
For instance, empty function, or some Jasmine spy.
So that you can assert whether it was code or not.
But that's pretty much it.
It doesn't do anything.
So that's the reason for this tiny wrapper, which is
something that you can see multiple times
in this source code.
PETE LEPAGE: Now you guys saw those change a lot.
At this point, we kind of expect and hope that we're not
going to see a lot more changes to the Window API.
Because we are at a point where things are really
starting to become more stable, the breaking changes
really are fewer and much further between.
You guys started on this two months ago?
VOJTA JINA: This editor was done couple weeks before
Google I/O. We did that for Google I/O. So that was a time
when there were many changes.
BRAD GREEN: This is true.
And although this API will not be changing, I think this
lesson still applies.
Because for me to be able to change my code, and if I want
to reorganize my code, using Angular's dependency injection
allows to just have a really good, flexible code--
VOJTA JINA: Exactly.
BRAD GREEN: --no matter what I want to do.
PETE LEPAGE: I think that's really good point.
For me, that was really the point where I realized, oh,
this dependency injection style.
That's really amazing.
Because you design something one day, and it works well.
But then the other day, it's completely broken because some
API changed.
So you fix it.
And guess what?
The other day, it's broken again.
BRAD GREEN: And it may not be an API.
It may be other developers you're working with.
It's the same if you're working on a product for a
customer and the requirements keep changing.
That's completely the same.
And so suddenly, the architecture of the original
design is not that great as it was.
And I really believe that the only way to manage and to keep
the code nice and clean, is just to keep refactoring.
And the point is that, once you have this dependency
injection that wires all these pieces together automatically,
it is super easy to refactor.
So you do it.
If it's difficult, you don't do it.

BRAD GREEN: Let's move on to the Settings controller.
The settings where we keep track of all your preferences
and where we synchronize them across all your devices.
PETE LEPAGE: Before we jump there, I just want to make one
quick comment to the folks who are watching.
If you have questions for these guys as we're going, or
as we're working through some of these examples and showing
you this stuff, be sure to post your questions to the
Google Developers Live page.
You can go to,
and click on the Live link, and post your questions on the
moderator queue just down below.
Because we want to take your live
questions as we go through.
So please, post your questions.
VOJTA JINA: I think that's what this is about.
PETE LEPAGE: Absolutely.
VOJTA JINA: All right.
So settings.
BRAD GREEN: So yeah, let's look at the Settings
Is that what we have up?
Again, this controller is almost empty.
I think that's another lesson that I learned during
building this app.
Which is, regarding to Angular, that I think it's
good to keep the controllers really lightweight, because
then it's way easier to move things around.
So for instance, I remember moving this Search dialogue.
And at that time, I had it inside controller [INAUDIBLE].
And it was kind of difficult to move it to a different
place on the page.
Because everything that is inside the controller is tied
to the position of the app, because the controller has a
specific position.
So my lesson was, put more stuff into services.

Most of the controllers are just publishing stuff into
scope, so they are accessible from templates.
BRAD GREEN: Fantastic.
So walk us through how this works, though.
VOJTA JINA: All right.
BRAD GREEN: Into the service itself.
VOJTA JINA: So Settings.
Let's open the Settings service as well.

PETE LEPAGE: And as you're opening that up, one of the
other things I'll comment on, all of this code is available
on GitHub today.
So you can go to the GitHub URL, which we can, in a
minute, put on screen.
But you can go to GitHub.
You can pull this code down.
And you can play with this code yourself.
You can go look in and see how everything works.
You can try seeing how all of these different services work.
If you want to try and move something from one place to
another, and see what you were just talking
about, you can do that.
So all this code is available for you to go play with.
It will work on Chrome today.

VOJTA JINA: All right.
So the Setting service.
That's the source of the [INAUDIBLE]
that keeps all the states about your settings.
And there's a bunch of other components that communicates
with the service.
So first thing is the view.
That's the part at the bottom, like here.
And the communication between the view and the Setting
service is down through Angular data binding.
So again, whenever a user changes anything-- like
whenever I change the select--
it immediately changes the model.
That's Angular business.
BRAD GREEN: We say model.
These are just variables in your app.
Just properties--
VOJTA JINA: Just objects, properties.
Another thing that is in the game is the ACE editor itself.
Because as you can see, most of these settings are actually
related to ACE editor.
And ACE editor has getters and setters.
So there is a tiny wrapper around ACE editor which
translates changes to this settings model, and calls
proper settings, getters and setters from ACE editor.
So for instance, if I change the theme, it will call ACE
editor set theme to something.
And the last piece is the storage.
Because as we mentioned at the beginning, all these settings
are synchronized, of course, across all the devices.
So at the bootstrap, the settings loads all the data,
all the settings from Chrome storage, Chrome storage sync.
And when you close the app, it saves the
settings back to the storage.
Now are you listening for events that may happen?
So if I'm on two computers, and I make a change on one,
Chrome fires an event that says, hey, this
data has been updated.
Are you guys listening for that today?
We don't.
But you are welcome to send us a pull request.
PETE LEPAGE: So that's one of the other cool
things you can do.
And we talked about this last week.
That you can say, hey, I want to go listen for events.
So that if you go update it on one computer, you get that
live update on the second computer.
VOJTA JINA: You could do that.
We did not, but you could.
PETE LEPAGE: And config settings for an editor, you're
usually not editing on two computers.
BRAD GREEN: Unlikely.
But I think it would be a cool demo.
It would be a great part of TextDrive.
And like you say, this is on GitHub.
We'd like to see everybody add to it.
How cool is it that there's a text editor that
anybody can play with?
You can add to your favorite feature to it.
That's pretty neat.
VOJTA JINA: So I think we might actually show the
dependency injection.
At least a little bit display--
BRAD GREEN: Yeah, we were talking
about dependency injection.
Maybe let's dive just a little deeper into it.
VOJTA JINA: Because what dependency injection does,
even this is a simple app.
The hard work is done by ACE editor.
BRAD GREEN: For sure.
VOJTA JINA: Let's be honest.
And still, we have about 12 services and four controllers.
The so that's a lot of components playing together.
And then, you need to wire all these components together to
actually get your app.
And that's exactly what dependency injection does.
So if you look into this concrete example.
So let's look into Settings controller.
So when Angular sees Settings controller, which is at the
bottom of the page, it says, ah, I need to instantiate this
So here is the constructor.
And it first looks into the constructor arguments, and it
sees, ah, I need Settings service first.
So it goes to instantiate Setting service first.
BRAD GREEN: And it knows this by the name "Settings." And
you're going to show us how we've told Angular, that when
you see Settings, create the service first.
VOJTA JINA: So the dependency injection, or Angular, goes to
settings, construct, and see, OK.
But in order to instantiate Settings service, I need to
create storage first, and et cetera and et cetera.
So this is the way dependency injection resolves all the
dependencies doing runtime.
And you don't have to worry about it.
Every component just declares, defines, its
dependencies, and that's it.
And this makes it super easy to refactor code.
Because anything like adding new stuff, like adding new
service, like maybe adding new features, or even extracting
stuff from existing service into new service--
it's super easy.
BRAD GREEN: And it makes your code very short, too.
Because normally, in your code, either you've got this
big, main method, where you're kind of wiring stuff together,
where you create something that it needs something else,
or you create that, or you ask for it, or you
have to locate it.
And here, you just ask for these things.
And they get automatically passed to your function.
VOJTA JINA: I think it really enables you to do refactoring
so you actually do it.
Because it's easy.
So why not?
PETE LEPAGE: All right.
So let's maybe let's review some of the APIs
that we used for this.
Do you want to take us through some of that?
VOJTA JINA: I think the most important API that we used was
a file system API.
So basically, reading all the files, and writing to files,
is done through chrome.fileSystem.
I think we can send links to docs afterwards.
So we've got the links to the docs.
But one of the things that's, I think, interesting about the
Chrome File System APIs that's different from the HTML5 File
System APIs, is that it allows you to open files anywhere on
your computer, right?
So that I can go edit that document that's sitting in My
Documents folder, or something else.
I'm not limited that specific set.
VOJTA JINA: Exactly.
PETE LEPAGE: I can also save anywhere across my computer.
So if I want to save it to the My Documents folder, or--
VOJTA JINA: And there are still a lot of security
So it should be secure for the user at first.
It's not going to let me just go randomly open a file and
not tell the user.
VOJTA JINA: So for instance, at this point TextDrive can't
re-open previously opened files, because there is no way
to open files without actually bringing up the pop-up.
So the user has to explicitly say, yes, I'm fine if
you open this file.
And you have writing permissions
to the file as well.
So File System is definitely the most important.
Then we use the Chrome Storage.
We are using Chrome Storage Sync so that it's synchronized
in between devices.
Again, the cool thing is that you have just the storage that
you write to and read from.
And it's synchronized across the devices.
You don't worry about that.

BRAD GREEN: There's one more.
So you want to talk a little bit about
Content Security Policy--
BRAD GREEN: So the Chrome apps.
We want them to run.
And users want to know that they're not going to do
nefarious things to their machine.
And so we need to comply with the Content Security Policy.
And Angular will implement this for you.
It'll set Angular into a CSP-compliant mode.
On Chrome, we can actually auto-detect this.
There's nothing for you to do.
On other platforms, we've got a tag you can use.
VOJTA JINA: There's a directive that you put onto
body, or an HTML tag.
You put NG-CSP.
And that would enable CSP.
Angular itself is pretty fine with that.
There is just one thing that we do.
When we instantiate a new function, which is something
that is not secure, so you're not allowed to do that.
Good, good, good.
So that's actually a change recently in Angular.
Because it used to be that, if I wanted Angular to go into
it's CSP safe mode, I had to go and put that into my head,
or into my body, off the bat, every single time.
But now, I don't have to do that.
So it makes my development a lot easier.
BRAD GREEN: Well, we worked together I this.
PETE LEPAGE: Absolutely
BRAD GREEN: This was something we explored
together, which was great.
PETE LEPAGE: This has been a really great learning project
for all of us, because we've been able to really go, oh,
building a real app?
Here's a problem that we've run into,
and a concrete example.
How do we fix this?
We found one, earlier today, where we were
talking about zooming.
On Chrome, you can do controls shift plus, and zoom in.
But if you're running a Chrome app, controls shift plus
doesn't zoom in on the Chrome app.
So as we are starting to do these demos, we went, oh.
Well, we're going to go file a bug on that.
So after our office hours today, go have a peek.
You'll probably see a bug in there, filed by one of us, to
say, we need to be able to support zooming
on our Chrome apps.
BRAD GREEN: Yes, for sure.
Well, fantastic.
So we've got URLs.
AngularJS is just at
For the V2 APIs--
we have a URL for that.
We can toss that up in a sec.
But you can also get to that always by going to, and clicking on the Chrome apps
link there.
You can get to all of the documentation
for the special APIs.
You can get to the documentation for just
generally the Hello World.
And you can also get to all of the samples that we have.
So beyond the TextDrive app that you guys have, we have an
entire GitHub repo, where we have probably about two dozen
different Chrome apps.
If you had a look at our Google+ developer page last
week, we showed controlling an AR Parrot Drone using a
gamepad controller through a Chrome app.
We filmed some more footage of it last night.
I tried to get the video together.
And I didn't get it.
But keep an eye on the Chrome developers
page today or tomorrow.
And we'll get that up.
It's pretty cool to be able to control a helicopter through a
Chrome app using a gamepad controller.
We're just going completely out of the box.
We want to make it possible for developers to write
applications that they just haven't been able to write on
the web before.
BRAD GREEN: And then the last thing, of course, is the URL
to GitHub for the TextDrive app itself.
We'd love to see some crazy pull requests
coming for that app.
PETE LEPAGE: That would be really cool.
BRAD GREEN: Please use it, and please add to it.
VOJTA JINA: I think we have a YouTube question?
Why don't we start jumping into the questions?
We've had a whole bunch come in in the meantime.
So the first question is, "Updating or rewriting jQuery
plugins using directives still feels a little bit foreign,
and could use some more real-world examples.
It would be great to have a commented version of some real
directives done correctly, such as the Angular
Bootstrap." Do you guys have plans to do
some more of those?
BRAD GREEN: Yeah absolutely.
Good question.
So there are a couple projects that do this.
One of them is called Angular UI.
It's not something we do, but part of the community of
Angular is building it.
Just go on GitHub and search for Angular-UI.
You can see a bunch of great examples there.
VOJTA JINA: This question is really related to Angular, but
it pops up very often.
And it really depends.
There are jQuery plugins that are, actually, easy to wrap.
And there are jQuery plugins that are not
that easy to wrap.
It depends.

To be fair, I think this is some place that we could
improve Angular.
We could make it easier to work with some of the really
key components.
And maybe we need to go talk to the jQuery guys.
So the next question is actually a
really interesting one.
From somebody in New Haven, Connecticut.
His comment was, "This makes me a little bit nervous,
because part of this page seem to have gone dangerously close
to inline JavaScript, in the style onclick and friends.
Do you have thoughts on this matter?"
So you're seeing a bunch of attributes inside the tags,
now, that we've added in Angular.
And this feels like, OK, that's just like onclick.
Why is that not just onclick?
And maybe, Vojta, you've got some comments.
But one of the key differences is that onclick is a global
name space entity, and it has all of the problems of
testability and leakage into the rest of your app.
VOJTA JINA: In general, you can say, I think pretty much--
BRAD GREEN: The Angular version does
not have this problem.
I think pretty much all the problems that this onclick
handlers suffers from, Angular does not.
BRAD GREEN: So it is a good question.
I think we've got a presentation tonight at our
meet up on Angular.
If you can join us for that or see the video afterwards,
we'll go into that in a lot more depth.
VOJTA JINA: It's going to be about directives.
PETE LEPAGE: So where can they find the video afterwards?
BRAD GREEN: If you go to our blog, just at,
and click on blog.
Or if you just go to, you'll be
able to find that.
PETE LEPAGE: So that'll be later tonight?
BRAD GREEN: That's right.
VOJTA JINA: Or there is a YouTube channel, I think.
BRAD GREEN: And there's a YouTube channel.
That's right.
Just AngularJS.
So Dennis wants to know why TextDrive isn't on the Chrome
Web Store yet.
And I think there's a good answer, but
I'll let you guys--
VOJTA JINA: I think the first answer is that it doesn't run
on stable Chrome.
BRAD GREEN: And as soon as it does, we'd love
to put it up there.
VOJTA JINA: Yeah, for sure.
PETE LEPAGE: So the big thing right now is for web
developers who are building Chrome apps, you can't upload
them to he Chrome Web Store yet.
We're still really working through and making sure that
we get everything stable, we get everything right.
We're not 100% positive that there will be no
more breaking changes.
We think we're there.
But we're not positive yet.
So we don't want to allow developers to upload code only
to find that, oh, we just made that one last breaking change
that we had to do and all of a sudden,
everybody's app stops working.
So we'll make some pretty big announcements, and do a
Hangout here when developers can start uploading those.
And we'll work with you guys to make sure that yours is one
of the first to get uploaded and available to folks.
So the next question is from Martin in Denmark.
But he says, "I love AngularJS," but he's not so
fond of JavaScript in general.
"Will we see Angular in some form of Dart?" And he's got a
little smiley face afterwards.
BRAD GREEN: That's a great idea.
I don't see any reason not to.
We've talked to the Dart team a bit.
We haven't started working on it, but yeah.
Sounds great to me.
VOJTA JINA: Angular is ideas.
It's not coupled to--
BRAD GREEN: That's right.
It's an--
VOJTA JINA: --a language.
BRAD GREEN: --idiom for developing.
And we're not tied to JavaScript.
Though we like JavaScript.
Though we like Dart, too.
So we did mention that the code is available on GitHub.
Denis did have a comment.
Not so much a question.
But GitHub is, apparently, not so happy right now.
You will be able to go grab it.
The URL that we provided will still work.
So you can go to that URL for the code, and
pull it down later.
VOJTA JINA: GitHub is awesome.
I'm pretty sure it's going to be OK in a couple of hours.
Hopefully it'll just be a couple more minutes.
I'm sure they're working pretty hard right now.
So this is a little bit of an in-depth questions.
So I'm going to try and read it as best I can, and not mess
it up too much.
So Project in subdirectory.
And they they added a base source tag that says
subdirectory, thinking the HTML5 URL would be
sudir/route1 and subdir/route2, and for older
browsers it would be subdir/#!route1, #!route2.
But instead, it came out as subdir/#!/route1.

Is that--
VOJTA JINA: I got lost.
PETE LEPAGE: Well let me show you this code.
It's the one highlighted in blue there.
And he's trying to figure out, is that probably a code bug
for him, or is that a config thing?
BRAD GREEN: It's probably a config thing.
But if you would post to the AngularJS mailing list, with a
snippet of your code, or a jsFiddle example, we'd love to
look at it for you.
And where can they go for the mailing list?
BRAD GREEN: So again, go to
And there's a menu called Discuss.
Go to Discuss.
And then the mailing list is there.
PETE LEPAGE: Excellent.
So for some of these things, it's a little hard for us to
really be able to dig into these.
BRAD GREEN: Could be a bug.
We'd love that, too.
VOJTA JINA: I think it's more likely about configuration.
PETE LEPAGE: All right.
So, "How do you determine if a jQuery plugin can be easily
incorporated using directives or not?" And this is from Vij
in New Jersey.
VOJTA JINA: I would say it depends how much stuff this
jQuery plugin does, with regards to dome.
As long as it can live inside a div or something, and there
do whatever it wants, it's fine.
But as long as it starts doing things like, very often, these
model windows and stuff, it does stuff like, oh, I'm going
to remove this is dome.
And I'm going to put it somewhere else.
And then I'm going to delete this.
And I'm going to create a clone.
And this is something that angular compile doesn't like.
Because once you change the structure, it's--
If they're very invasive to the entire page, it can be
VOJTA JINA: Especially if you need angular binding inside
this component.
BRAD GREEN: Though in the angular-UI project, I know
that there are some examples of those type of things, like
the modal dialogues.
So go take a look.
And I know some of them use the Bootstrap code for that
instead of jQuery UI.
But I think you can get the same effect you want.
VOJTA JINA: Yeah, but I think, actually, Twitter Bootstrap
might be, in most of the cases, easier.
Because you can just take the CSS--
BRAD GREEN: That's right.
VOJTA JINA: --and do the JavaScript part with Angular,
which is actually way easier and faster.
So I think that--
We are big fans of Twitter Bootstrap for that reason.
And it looks great.
PETE LEPAGE: It is very pretty.
We're almost out of time.
I want to encourage anybody to add any other questions they
have to our moderator page.
But one of the things that I wanted to say is, in the
learning that you guys have been doing building Angular,
and building Chrome apps, what's the biggest learning
thing that you guys have taken away in terms of building a
Chrome app that you think our viewers would
learn the most from?
BRAD GREEN: Vojta, you did all the work.
So maybe you should answer.
VOJTA JINA: Well, I think we mentioned pretty
much all the stuff.
So with regards to Angular, definitely keeping controllers
light, and putting more stuff into services.
That's one thing I learned.

I learned--
BRAD GREEN: What do you think about building an app
versus a web app?
Anything specific there?

VOJTA JINA: I don't know.
I ended up wrapping all the APIs into services very often,
so that I have just really tiny wrapper around the
service that I can mock up around the service.
BRAD GREEN: This was good, because sometimes there is a
difference between running it as a web app and running it as
an app on Chrome OS.
VOJTA JINA: Good point.
BRAD GREEN: And this dependency injection will
allow you to switch it in a very, very transparent way.
VOJTA JINA: I think we have a good example of that.
And that's actually the storage.
Because we said we are using Chrome Storage Sync.
But if you ran this code just in regular Chrome, there is no
Chrome Storage.
So we fall back, and we use local storage.
Let me actually open this up.
The local storage is completely synchronous.
But Chrome Storage Sync is completely asynchronous.
And you don't want to have service that is sometimes
synchronous and sometimes asynchronous.
VOJTA JINA: That kind of sucks.
And it's difficult to work with that.
So what I did is just wrapping this service, and basically
creating wrapper.
So that even the local storage is asynchronous.
And the rest of your app doesn't have
to worry about that.
It's just asynchronous all the time.
BRAD GREEN: We did an impedance matching exercise,
so that you can run as an app or on the web
with the same code.
VOJTA JINA: And again, with dependency injection, you have
these two versions of this service.
And you just inject whatever version you need, depending on
the platform.
BRAD GREEN: It's a lot cleaner than having a big switch
statement, or a whole bunch of ifs all over your code.
VOJTA JINA: Better than having one storage with a lot of ifs.
I think it's easier to read.
Well, I want to thank you guys.
We're pretty much out of time at this point.
And you guys have done, I think, a really great job of
introducing our viewers to Angular, and talking about
some of the learnings that you've had
building Chrome apps.
As well as where they can go learn more information about
taking TextDrive apart and using it themselves,
understanding how it works, and some of the best practices
for building Chrome apps.
We're going back again next week, next Tuesday, same time.
We're just figuring out what our plan for next
week is right now.
But today, most of the other guys who you're used to seeing
aren't here, because we're doing a hackathon.
And we've got a whole bunch of people who are sitting down,
building apps, doing some really cool stuff.
So I think, probably next week, we'll spend a little bit
of time talking about the cool stuff that everybody built,
some of the lessons learned, and giving you some of the
great lessons, and showing off some really cool things.
So with that, I want to say thank you to Brad and Vojta.
And thank you for tuning in and watching.
And we'll join you next week.
BRAD GREEN: Thanks for having us.
This was fun.
VOJTA JINA: Thanks for having us.
PETE LEPAGE: Thanks, everybody.