Components in a static site too

In the 2nd part of this series, we learned about some basics of rendering a view. We ended that topic by having a look at the router. The router just had one path, the root (/), which was mapped to a single component called the HelloComponent.

Here’s what we’ll do in this post:

  • Examine the HelloComponent
  • Add a new route, and a new component to handle the route
  • Add a nav link to take the user to the new route
  • Render another component inline without routing

HelloComponent

As you can see, the HTML code for most of what you see when you navigate to http://localhost:8080 comes from this file. So how does Vue know where to render the contents of this component? If you recall, the App.vue, the parent component, has a tag called and I mentioned that this is the output for any component that is routed to by the router.

Add a new route, and a new component to handle the route

Create a new file under the components/ folder. Let’s call it TestComponent.vue. And paste the following content.

Yes, I realize it doesn’t do much. I wanted to show you what a basic component looks like. It doesn’t need to have anything more than just that. With just that much content, you get a valid component. You should be able to imagine now, how easy it is to create a component and have your entire site split into pieces (components), that all come together eventually in the browser.

But wait. We are not done adding the component. We just added a file called TestComponent.vue but we haven’t really used it anywhere. So let’s add a new route to the router/index.js file.

Your router should now look like this:

We just added a new route to the router called /test, which routes to the newly-created TestComponent. Let’s test this out by going to: http://localhost:8080/#/test. You should see most of the content replaced with just the word “Test”. This means our new component has rendered. Great. We confirmed our new component to be working by manually going to the /test route.

Add a nav link to take the user to the new route

Let’s look at adding a route-link so that the user can navigate to this newly-created component of ours. Update the App.vue with this. Somewhere inside the <template> tag, add this markup

<router-link to="/test">Go to Test</router-link>

Vue will take care of the rest. It will render the router-link as an anchor (<a>) tag. You could do this programmatically too, if you don’t want to use an anchor tag. Refresh your browser and you should see a Go to Test link on your page. Click it. You should now see the contents of the TestComponent. That was it.

That’s it. We just learned how to use components in Vue to compose our app of little pieces, which are building blocks for a larger site or web app. I highly recommend reading more about VueRouter here.

Render another component inline without routing

So we saw how we could link to a custom component. What if we simply want to render another component inline, in the context of a parent component? Yep. You can do that too.

To do that, let’s first remove the <router-link> tag, and update your App.vue to this:

Then, go to http://localhost:8080 and you should see the contents of the TestComponent rendered inside the contents of App.vue, which also happens to consist of the contents from HelloComponent. So instead of replacing the contents from HelloComponent, we just augmented the contents of our new component in there.

Since you are rendering the component inline, there is no need for that new route that we added to the router/index.js. You can remove the /test route from it as well, if you’d like.

 

Advertisements

Remote debugging an embedded WebView in Android

And there I was, thinking that I was done with AzureStorageExplorer for Android v1.0.0. But, nope. In my last round of testing, I couldn’t even login using my work account. The Sign In button didn’t do anything. I went back a few versions to see if the Android update for WebView could have done something to break it. That wasn’t it. The OAuth client library I was using had the recommended code for enabling Javascript in the WebView client so I knew that wasn’t it. I was able to login through the Azure OAuth flow using my personal Azure account. So, I knew there was something about the enterprise account login screen, which could have changed recently that ended up breaking the authentication in the app. It turns out that it did. Read on to know how I found out.

The first step was to prove that something was indeed broken in the login screen for enterprise accounts in Azure in embedded WebViews. To do this, I looked up Chrome’s remote debugging options and found this page describing how to remotely debug WebViews in mobile apps. So, I enabled the setting as recommended by Google, which required adding this piece of code in my activity’s onCreate(Bundle) method.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  WebView.setWebContentsDebuggingEnabled(true);
}

I ran the app, launched Chrome’s Developer Tools, and connected to the app’s WebView. This is what I found..

2016-12-26_09-49-21

That last error in the console is what was logged when I pressed the Sign In button after entering my work account credentials for Azure. It turns out that the page’s JS now has code to store something in the browser’s localStorage. The reason this isn’t a problem, if you were logging into Azure through a desktop or even a mobile browser, is because localStorage is enabled for every site by default in the non-embedded browser view. But for a WebView in an Android app you need to explicitly enable the DOM storage, just like you need to enable JS through the WebSettings class.

After finding this, it was easy to know where I needed to make the fix. So, I set out to fork the source repo of the OAuth library I was using, made the necessary changes and created a pull request. If you are using the same library and have run into this issue, you could clone my repo and build the project to produce the patched .jar (or an .aar), which you can use in your project directly until the author of the library can get to my pull request (if at all!).

left-right

I created a new public repo on my GitHub page. Check it out.

iOS Style Scroller For PhoneGap App

I have moved the files to GitHub at https://github.com/praneetloke/SpinningWheel-Wrapper

I am going to show you the extensions I made to the spinningwheel script created by the developer of the popular iScroll script. The spinningwheel script by Matteo works great just out-of-the-box. It’s much better than mobiscroll. Spinningwheel allows you to add slots of custom data which means if you are about to use spinningwheel for a date picker then you have to write your own logic for handling the days/months logic and then there’s the leap year calculation for February. But working with spinningwheel was easy and interesting. Matteo’s code is always organized as you can see from the source of his iScroll and SwipeView scripts. It was just a matter of writing down what extensions I wanted to make to his script. So, I first started out by realizing that I wanted a wrapper around the spinningwheel; that’s where the second file in the attachments comes to use. Most importantly his scripts are always written in regular javascript and always has a destroy method (which is very useful when you want to manage memory). Writing in regular javascript means no external dependencies. Following the same guidelines I too made the extensions in regular javascript and also the new events you can subscribe to in the spinningwheel are written in regular javascript. Another advantage of using spinningwheel over mobiscroll is spinningwheel uses translate3d for the transitions which means it will look and work awesome on iOS devices and even on higher end Android devices (phones and tablets). Oh and another one again is that since spinningwheel is written in regular javascript it easy for you to make extensions to it based on your needs unlike mobiscroll which relies of jQuery selectors heavily which means if you are not using jQuery, good luck!

The ScrollWheel class I wrote allows you to use the SpinningWheel instance as a singleton object. You can create an instance of ScrollWheel and pass in parameters like ‘date’, ‘time’ or ‘custom’ (if you want to use custom slots). Most of you would want to use the date and time presets that I created. The custom presets allow you to simply bind a click listener to text input and show the spinning wheel without having to do any extra work.

As you will see in the ScrollWheel.custom file, I have set the cancel action to call the post callback (which you would have passed when an instance of ScrollWheel was created) immediately and a null value for the results. In your post callback be sure to add a check for the results array so you don’t accidentally update the existing value in the text box (if any) to null. You can see what I have done with my post callback in ScrollWheel_Init.

The HTML element that you need to have to actually show the spinningwheel is pretty simple. Just use something like this (or exactly):

<input id=”timePicker” type=”text” readonly=”readonly” onfocus=”preventFocus(this)” onclick=”showTimePicker(event, this.id, this.value);”/>

or you can modify the showTimePicker function to take just the event object as a parameter and modify the click handler in the element to:

<input id=”timePicker” type=”text” readonly=”readonly” onfocus=”preventFocus(this)” onclick=”showTimePicker(event);”/>

Or you could alternatively ‘bind’ to the click event using jQuery or Zepto as well. I will not explain the logic of updateDates since it is pretty straight forward. In spinningwheel.js, you will find that I have added a new event handler that you can set via an instance of ScrollWheel (or directly via SpinningWheel) called scrollEndAction. This is what you need to set if you want to subscribe to the scrollEnd event and have a handler invoked every time the user stops scrolling a slot.

A snippet of the handleEvent function in spinninwheel where I added the invocation of the scrollEndAction

else if (e.type == ‘touchend’) {

if (e.currentTarget.id == ‘sw-cancel’ || e.currentTarget.id == ‘sw-done’) {

this.tapUp(e);

} else if (e.currentTarget.id == ‘sw-frame’) {

this.scrollEnd(e);

//console.log(“calling scroll end action”);

setTimeout($.proxy(this.scrollEndAction(this.activeSlot), this), 100);

var self = this;

setTimeout(function () {self.scrollEndAction.apply(this, [self.activeSlot]);}, 100);

}

}

There are two new public functions I have added to the spinningwheel.js, called showSlotValuesAfter and hideSlotValuesAfter. These functions will allow you to pass the slot index (0 based), the last key of the json object that the slot holds as values, and the number of values you want to show/hide after that last key. The reason for these is to help with hiding the dates that don’t apply for a particular month and then showing them again when they are applicable. Look at updateDates to understand how this is done. I have also made sure that when you call on these functions the corresponding slot’s max scroll boundary is updated so that it doesn’t allow you to scroll over the ‘hidden’ values. Find out why I call them ‘hidden’ values. 

The good thing about the wrapper I have written is that it checks if an instance of a ScrollWheel is already open and if so it won’t allow you to open another one. This was the only problem with spinningwheel out-of-the-box. SpinningWheel is a global instance and you have to manage it. If you open too many instances at the same time you are likely to chew up memory from the browser and can see significant impact to the performance of the page and even states and values will be corrupted. This is why I wrote the wrapper to make sure that I take care of this.

There is no technical reason for me to name the wrapper as ScrollWheel so you can change the name of the class to whatever you like. Just remember to retain the names and the original license at the top of the files. Although I claim no responsibility for the stability of these extensions and no support for them, I do know that they work because I use them and you can ask me for help as long as you don’t blame me for anything after all you downloaded them, I did not force you to.

A word of caution about spinningwheel’s goal. It is to be used with webkit based browsers. It was created to be used with iOS and Android phones as they implement the WebKit framework and also it is original intended to be used with touch enabled WebKit platforms which means it will not work with desktop browsers (Chrome, Safari, or Opera) out-of-the-box but there’s good news, download the touché framework I blogged about last week and it should work like a charm. I may look into porting this for the WP7 but not yet. I’ll tackle that when I get there but if you do be sure to let me know. It’ll save me some time 🙂

Be sure to ask me if you don’t understand the sources. Just don’t be a duck about it. That’s it for now. Enjoy your new spinningwheel!