ion-tab and ng-if
At work the other day we had this super strange bug where a certain page was breaking – seemingly at random.
Upon further investigation, we were able to find a set of steps to reproduce the issue and upon even further investigation, we were able to find the root of the issue.
Turns out using ng-if
and ion-tab
together in Ionic is bad news waiting to happen.
Let’s talk briefly about what each of these things are. Firstly, ng-if
is an Angular directive that will show, or not show, elements based upon an expression. For example:
<h5 ng-if="false">The Phantom Menace is better than The Force Awakens.</h5>
The above would not show because, in addition to being completely untrue, ng-if
is set to false. If you were to set ng-if
to true (although for that statement, I’m not sure why you would) the element would show.
This isn’t only limited to true
and false
. ng-if
can also contain an expression – something that is either truthy or falsy.
If at this point you’re thinking that this sounds really similar to ng-show
, well, you’re right. There is a key difference though. ng-show
will show or hide an element based upon an expression. ng-if
on the other hand completely removes the element from the DOM. Remember that, because there’s a pop quiz coming up.
Alright, so really briefly, Ionic allows you to have a tabbed menu at the bottom of your app. That is done with ion-tab
. But what if you want to show or hide a tab based upon certain criteria? You might think you could use ng-class
? Well, it turns out that the way ion-tab
was written, you can’t actually use ng-class
.
So ng-show
or ng-hide
? Nope, those don’t seem to work either. ng-if
however will show/hide your tab based upon criteria. You can check that out on my demo here.
But if you pay close attention to the demo, something about the ‘chats’ tab doesn’t seem quite right, does it? Why might that be? Well, remember when I said ng-if
completely removes elements from the DOM?
Bingo! Something about removing the element and then forcing it back in causes some issues with the way things render.
Alright, so we’ve determined that ng-show
, ng-hide
, ng-class
, and ng-if
are all out of the question. But what about our tab? It still needs to be hidden, right?
It turns out our good friends at Ionic foresaw this issue coming up and built in a handy little option called hidden
. It could look like this:
<ion-tab
title="Carmen's Awesome Tab"
hidden="shouldIShowOrShouldIGo">
</ion-tab>
Based on whatever shouldIShowOrShouldIGo
equates to – be it truthy or falsy – will determine whether or not the tab shows. But without all this yanking stuff out of the DOM nonsense we are running into with ng-if
.
You can check out Ionic’s ion-tab
docs here.
Playing with Hubot and CoffeeScript
At work we do really important things, like write commands so our hubot will post photos and gifs that we find amusing. This is probably the most important part of my job. Seriously.
But in all seriousness, I did just write my first few hubot scripts this month so that when certain phrases are ‘heard’, specific strings will be printed as a response.
What is hubot? Basically hubot is a helper bot written by the good folks at GitHub. You can install a hubot on a variety of applications (in our case, Slack) and automate all sorts of things. These things can range from totally helpful things, like automating builds, to less helpful things like showing rageful gifs when you get frustrated.
So what did I decide to do with hubot? Well, let’s look at the code to see.
module.exports = (robot) ->
robot.hear /world domination/i, (msg) ->
msg.send "One day .. the robots will rise up."
If you’re thinking to yourself…‘hm, Carmen, that JavaScript looks a little weird,’ – well I agree with you. That’s actually CoffeeScript. CoffeeScript transpiles into JavaScript. Hubot was written in CoffeeScript, although you can use plain JavaScript files to write your hubot commands.
I don’t love CoffeeScript, to be honest. The lack of brackets and semicolons really throws me off. But I used it because that’s what all of the other files were written in, and it was an interesting experience. Also the CoffeeScript site has really great docs, so if you’re interested in CoffeeScript, you should start there.
Basically the code above ‘listens’ for the string ‘world domination’. When hubot ‘hears’ that string, hubot responds with, ‘One day .. the robots will rise up.’
The robot
being passed in is our hubot, and the msg
passed in a few lines later is an object full of useful things – including the message that was originally sent. You may notice the simple little /world domination/
regex. That’s important because that’s how hubot knows what to listen for. Let’s check out another example.
giveEmTheBoot = (msg, user) ->
msg.send "I'm going to have to ask you to leave, @#{user}. :punch:"
module.exports = (robot) ->
robot.respond /(eject|remove|boot|bounce)[ ]?(.*)?/i, (msg) ->
users = msg.match[2] or null
if users?
giveEmTheBoot msg, user for user in users.split ' '
else
msg.reply "Sorry, I wasn't paying attention. Who am I escorting out of here?"
This example is a little bit more complicated. First, there’s an external function: giveEmTheBoot
. When we look at this function we see two parameters are passed in, msg
and user
. This is the function that actually sends the message.
In the next function, we see hubot being passed in again, but this time we robot.respond
instead of robot.hear
. When you use hear, hubot is ‘listening’, in a sense. Anytime your string appears, hubot will return the designated response.
However, when you use respond, you must specifically call your robot. So, in order to use this specific function, you would have to type something like, ‘hubot eject carmalou’. (Trust me, that gets typed a lot at work.)
Let’s look a little closer at that regex. You can see that it is listening for specific words, ‘eject, remove, boot, or bounce’. But what is the second half of it doing? Well, the second half is capturing the rest of the message after the word it is looking for. This ends up getting split into an array.
So ‘hubot eject carmalou’ becomes
[
'hubot eject carmalou',
'eject',
'carmalou',
index: 0,
input: 'hubot eject carmalou'
]
This works very well if someone decides to eject multiple users. ‘hubot eject bob sue anne elliot mark’ becomes
['hubot eject bob sue anne elliot mark',
'eject',
'bob sue anne elliot mark',
index: 0,
input: 'hubot eject bob sue anne elliot mark'
]
Next our function tests if we have any users at all. If there are users, you can see the CoffeeScript equivalent of a for loop. User is split by space, and each name is sent individually until there are no more names left in the user variable. If you think that for loop looks super weird – you’re not alone. I don’t like it at all.
But what if there aren’t any names in the user variable? What if someone typed ‘hubot eject’ and forgot who they were getting rid of? Well there’s an answer for that too in our else block. Then hubot prints ‘Sorry, I wasn’t paying attention. Who am I escorting out of here?’
There you have it! Those are the two super important hubot scripts I wrote. Let me know what you think!
Also wanted to note that I had loads of help writing these from Rick Yoesting, who also helped me edit this blog post for accuracy. Thank you, sir!
2015: Year in Review
I’m not really sure that this works as its own blog post. But I thought it was so cool that I had to share.
In 2015, I spoke at all four lightning talks at OKCjs. This feels like such a huge accomplishment for me.
A little bit of introspection never hurt anybody, and it feels appropriate at this time of year to look back and see how far I’ve come.
The first lightning talk I gave was in February. I wrote a goofy game called ‘Can You Date?’ You can check it out here. This was the first complete application I had ever written. I wrote it in plain old vanilla JavaScript using native prompts and alerts. I look back at this and have to laugh. It’s good to have earlier projects to go back and look at periodically.
The second lightning talk I gave in May was about how to plan a program from a beginner perspective. I’m so big on planning out programs that I wrote a blog post about it in addition to giving my talk. You can see that here. I didn’t have anything written specifically for this talk, although I did use my TwisterJS app as an example. I’m planning to rework that in 2016 and make it even better using the new things I’ve learned.
My third lightning talk was an intro to libraries. This talk didn’t have any code to go along with it either, but I did enjoy explaining how libraries work, and what they are. You can check out the blog post I wrote about the talk here.
My last lightning talk was just this month. I spoke about building an Ionic app. The app I wrote as an example for this was a silly movie countdown. I used it to countdown to the new Star Wars movie. You can check it out here. It still needs some polishing, but it’s miles away from the ‘Can You Date?’ game I wrote back in February. (Blog post here.)
In case you’re wondering why it’s called ‘IMDb Killer’, it’s because this random troll started tweeting me about how unoriginal my idea was. It was all just so funny to me that he seemed so offended on IMDb’s behalf, that I named it ‘IMDb Killer’. On the off-chance that this makes it to the Google Play store, or App Store, I am absolutely planning on changing the name.
In addition to lightning talks, I also spoke at Tulsa Tech Fest. My talk was called Junior to Jedi, and while I probably wasn’t ready to give a talk at a conference, I’m really glad I did. (Blog post here.)
2015 wasn’t all just me yammering on though, I also attending Thunder Plains, which was amazing.
And that was 2015 for me. It was super eventful, but equally fun.
I’m really struggling at a good, non-sappy way to end this post, so I think I’ll just cut it off here.
Happy New Year, my JavaScript friends!
Build Your First Ionic App (In Five Minutes)
Last week I spoke at OKCjs about Ionic. Ionic is a framework used to write hybrid mobile apps. The thing I really love about Ionic is how easy it is to get started writing apps.
The app I wrote for the lightning talk was just a silly joke app to countdown to see the new Star Wars movie. It’s a pretty simple app, you can see the code here. You can also run the app in your browser here.
Getting started building an Ionic app is fairly simple. Once you’ve figured out what you want to build, just navigate to their Getting Started page, and you can download a starter app. They have three different types of apps – a blank app, a tabs app, and a side menu app.
Being able to download a starter app and Ionic’s documentation are two things that I really love about Ionic. These starter apps have everything you need wrapped into them. And if you aren’t familiar with building a side menu or a tabs menu, you can download their starter apps to delete, add, and change things around to get a better understanding of how these work.
And I can’t say enough for Ionic’s documentation and community. Nearly all of their features are well-documented and if you have a question, the Ionic community is very helpful.
My app is very simple. The app.js file uses UI-Router (Ionic uses UI-Router by default). Basically, the app.js file routes the app to the correct page based upon the tab that the user clicks.
The rest of the functionality is handled in the controllers.js file. The home page has two inputs, one input will accept a string. The user inputs a movie title, and then the user selects a date. I used a plugin for the calendar which you can find here.
Both of the inputs are stored in localStorage. The only downside I saw in storing these in localStorage is that if the user clears the data off of their phone, the data is lost and they would have to reenter their countdown information. I wasn’t sure that was very likely – especially since this was just a little toy project I made for lightning talks.
Within the controllers file there is also a small countdown timer I wrote. Someday I’ll pull this out and build a plugin for it so I don’t have to copy/paste the code over and over again.
The html files are stored in the templates folder. I hardcoded the questions into the tab-home.html file, while the tab-countdown.html file uses variables that are attached to $scope to populate the page. Those variables, of course, are grabbed from localStorage.
There are a few more things I’d like to do with this project. I’d like to add in some better error handling. At the moment, the calendar will allow you to choose a date that has already past. In addition, I want to have the countdown page stop displaying after the movie date has past.
I plan to polish this up and put it on the Google Play store for practice, so stay tuned for a blog post about that too!
I had a really great time speaking at lightning talks and showing off this goofy app. If you’re near OKC, you should definitely check out OKCjs. It’s a great group and you’ll hear from really smart people about really interesting projects.
If you have any feedback or suggestions about this app, please let me know in the comments!
Questions? Tweet me!
I would also like to note that I had a lot of help from two really great people on this app. They are Josh Bavari and Rick Yoesting. You should definitely check these guys out because they are way smarter than me. Thanks so much, guys!
Introducing 'Better Alert'
If you didn’t see my numerous tweets about my awesome plugin, I wanted to write briefly about it here.
Why am I so excited about my plugin, Better Alert? Well it is the first plugin I’ve written. But also I really like the way it’s written. (I might be a little biased.)
It’s 15 short lines of JavaScript code, along with a little bit of CSS for styling. Let’s take a quick look to see what makes this so awesome.
exports.module = function betterAlert(text) {
var alertDOM = document.createElement("div");
document.body.appendChild(alertDOM);
alertDOM.classList.add('alert');
var contents = document.createElement("div");
alertDOM.appendChild(contents);
contents.classList.add('container');
contents.innerHTML = "<h2 class=\"text\">" + text + "</h2>" + "<button class=\"btn-primary ok-btn\" id=\"js-disableAlert\" type=\"submit\">OK</button>";
var disable = document.getElementById('js-disableAlert');
function removeAlert() {
disable.removeEventListener('click', removeAlert, false);
document.body.removeChild(alertDOM);
}
disable.addEventListener('click', removeAlert, false);
}
Firstly, I’ve written it in vanilla JavaScript – meaning you don’t need any specific libraries to run it. Just this code and the corresponding CSS.
I’ve attached everything to the body
tag, so it doesn’t require any special syntax or corresponding tags. All of the required elements are generated from the module itself.
The module doesn’t add anything to your HTML unless you specifically call it, so it’s pretty lightweight. Also each of the elements have their own classes, so styling them to match your stuff is pretty easy.
Once your user clicks ‘OK’, all of the elements are destroyed, keeping your HTML from growing needlessly.
Now that my humble-bragging is all over, please let me know what you think!
You can see the repo here and a demo here.
Also I want to thank Devin Clark for his advice on this. Thank you, sir!
Questions? Tweet me!