http://wghenderson.comNodeJS RSS ModuleThu, 22 Feb 2018 06:24:31 GMT60This tutorial walks through integrating Bootstrap with Lavaca's Starter Application. A sample git repo of this tutorial's end result is available on my GitHub.

Install Bootstrap

Installing dependencies in Lavaca is easy, thanks to Bower. Bower is great for managing client-side dependencies, in-fact Lavaca Starter uses Bower to install Lavaca's core library. To install Boostrap add a new dependency in the bower.json file.

"dependencies": {
"bootstrap": "~3.0.3",
"lavaca": "latest"
}

Then open up a terminal and cd into the project's root and run:

'$ bower install'

During the install, it may ask what version of jQuery to use. Select the first option to use Lavaca's jQuery version.

Shim Bootstrap for RequireJS

Bootstrap provides some jQuery plugins to breath life into typical UI components like modals, popovers, and tooltips. These components can be shimmed individually or all at once. For simplicity lets shim the entire library.

In order for Bootstrap's JavaScript components to play nice with jQuery in a RequireJS setting we need to shim in the library. Open src/www/js/app/boot.js and add a path and shim entry.

This adds an alias for bootstrap's path to the components directory. The bootstrap module is now available by simply requiring it like require('bootstrap'). The shim entry allows us to define jQuery as a dependency of bootstrap, which prevents bootstrap from loading before jQuery.

The final step in adding Bootstrap's JavaScript components to our project is requiring the module. Since bootstrap just adds plugins to the jQuery namespace, we only need to require the module once. A logical place to add the module is in src/www/js/app/app.js.

To LESS or not to LESS

Lavaca Starter uses LESS out of the Box. Bootstrap gives the option of using LESS or compiled CSS. The LESS option is recommended since it is the most flexible and fits nicely into a typical Lavaca app workflow.

To use Bootstrap's LESS files, just import them into src/www/css/app/app.less.

If you don't plan to theme or make use of the LESS variables you can simply link components/bootstrap/dist/css/bootstrap-min.css and components/bootstrap/dist/css/bootstrap-theme-min.css into src/www/index.html. The only gotcha here is the components directory isn't copied by default during the build process, so your app won't work unless you alter the Gruntfile.js.

Conclusion

The default styles for HeaderView and HomeView are not really bootstrap friendly, so you may see the Lavaca logo is misaligned when you run grunt server. These styles are meant to throwaway anyways, so feel free to dump them and start over.

Questions or Feedback? Hit me up in the comments or on twitter @wghenderson

Lavaca Developer Tools an extension for Chrome DevTools

This extension adds a Lavaca panel to Chrome DevTools allowing developers to take a bird's-eye view of their Lavaca application. It features tools for visualizing view hierarchy, inspecting models, and examining defined routes. This extension also adds sidebars to the elements panel for inspecting the view and model associated with the selected element.

Close and re-open developer tools if it's already open and refresh your browser

Submit your pull requests :)

Features

Views Tab

This tab allows you visualize your application's view hierarchy and inspect the models associated with the rendered views. Hovering over each nested view will highlight its placement in the page. Clicking each view will show the selected view's model in the right column.

Routes Tab

This tab shows the data associated with the defined routes for your application. Including the pattern, controller type, controller action, and additional parameters.

Options Tab and Debugging Optimized Apps

Debugging applications optimized with Lavaca's build process require a namespace before the application can be recognized. To add a namespace to your optimized Lavaca app, edit the applications amd-dist config in the Gruntfile.js. Add an exports option with the variable to assign to the window. Note applications that use require.js don't require a namespace, so during development this is not necessary.

Create a new build running grunt build and deploy. Then add the namespace to the options tab, in this case the value would be myAppsNamespace. Once added, refresh the page and debug as usual.

Elements Panel

The Lavaca View Properties and Lavaca Model Properties sidebars expose the current view and model in the selected elements scope. If the selected element is not associated with view it defaults to the view on the highest layer.

Console Variables

The sidebars also add the current view and model references to console.

$view The current view in the selected elements scope. Defaults to the view on the highest layer.

$model The current view's model in the selected elements scope. Defaults to the model of the view on the highest layer.

Questions or Feedback? Hit me up in the comments or on twitter @wghenderson

]]>http://wghenderson.com/introducing-lavaca-developer-tools/562521d0-6d25-4bc5-81aa-90d41fa7f690Wed, 04 Dec 2013 17:09:05 GMTThe goal of this tutorial is to build a Lavaca app that contains an authentication flow for user signup, login, logout, and password reset with Parse. The end result should provide a seed for future projects or tutorials exploring Parse and Lavaca.

Project Setup

If you haven't already, pull down a copy of lavaca-starter and follow the Getting Started instructions to setup your dev environment. If you would rather just follow along the completed source of this tutorial, you can grab it from my github.

You will also need to setup a new app at http://Parse.com. When creating your app, make note of the Application ID and Javascript Key, we will use these in our app to initialize the Parse JavaScript SDK.

Install Dependencies

All client-side dependencies in Lavaca should be managed by Bower where possible. For this tutorial we'll need to add the Parse JavaScript SDK and bootstrap as dependencies in ./bower.json.

Each route is mapped to a controller type with a specific action. Optionally you can pass data to the controller action. Note the {bypassAuthentication: true} flag, we will use this to unprotect these routes in ./src/www/js/app/net/BaseController.

Authentication Controller and Logic

Before we stub out the AuthenticationController, lets add some logic to our BaseController to handle cases where the user is not logged in. Give this code a quick skim and then replace ./src/www/js/app/net/BaseController.

You'll notice we overwrote exec. This method calls a controller action with its parameters and history state. It is also the logical place to test if a user has sufficient permissions to visit the specified controller action and redirect them to the login route.

We can check if there is currently an authenticated user by casting a boolean from the return value of Parse.User.current().

isAuthenticated: function() {
return !!Parse.User.current();
}

Since we don't want to redirect all routes to the login screen, we added a flag to bypass authentication.

The first action is to handle logout. Parse makes this easy for us with a simple method call. After the synchronous call to logout, we unset the user from the state model and redirect the user to the login screen. The return statement is important here. Every controller action should return a promise allowing the router to properly dispose of the controller.

The login action ensures the user is logged out then presents the LoginView to ViewManager to load. Lastly, the action updates the history state with the state, title, and url. This common pattern shared by all of the other controller actions.

Login View

Every view requires a template. Our login view template needs a form to collect the username and password. We also need links to the forgot password flow and account creation. Create a file called ./src/www/js/templates/login.html with this markup.

In the constructor of the view we add an event listener to intercept the form submit event.

this.mapEvent({
form: {
submit: this.onFormSubmit.bind(this)
}
});

When the form is submitted, we grab the email and password values and login the user. If the login is successful, we set the current user on the state model broadcasting to the rest of the application that a user has logged in. Later in this tutorial we will use the state model to conditionally show a logout link when a user is logged in. Finally, we execute the index route to take the user home.

If we were to try to load our application as it stands right now, RequireJS would error out trying to find our views. But, I am kind of interested what the app is looking like, so lets comment out the unused actions and views in our authentication controller.

The SignupView should also function very similarly to the LoginView, but instead of logging in the user on form submit we create a new account. Create a new file for the signup view at ./src/www/js/app/ui/views/SignupView.js.

Here we create a new instance of a Parse.User and set some properties on that user. We then call the signUp() method, which posts our user data to Parse for account creation. On success, we update our state model with the current user. The newly created user is logged in automatically by Parse, so when we execute the index route the user should pass authentication without a redirect.

Once you have completed this step, the app should allow you to create a new account. Make sure your dev server is running a visit http://localhost:8080/signup and create an account.

Logout and Header

Im sure you have noticed that once your logged in, you stay logged in even if you refresh the page. Parse stores the current user in LocalStorage under the key Parse/{app_id}/currentUser. To logout open the webinspector console and run.

require('lavaca/mvc/Router').exec('/logout')

We can't expect our users to logout this way, so lets update the header to add a conditional logout link and look more bootstrappy. Replace ./src/www/js/templates/header.js with:

In order for our HeaderView to be redrawn properly when a user logs in or out. We need to update the scope of the redraw method in ./src/www/js/app/ui/views/controls/HeaderView.js to redraw the .navbar-nav when the model changes.

onModelChange: function() {
this.redraw('.navbar-nav');
}

In order to beautify the bootstrap header replace ./src/www/css/app/HeaderView.less with some new styles.

Again, onFormSubmit(), is where the action lies. Parse provides the method requestPasswordReset(). When called with a valid email, an email is sent to the user to verify the request. The email contains a link to a password reset form hosted by Parse.

On success or failure of the requestPasswordReset() method, we redraw the note with a message indicating the result.

Conclusion

By the end of this tutorial you should have a working Lavaca application integrated with Parse that contains, account creation, login, logout, and password reset. Although this application relied on Parse as a service and model layer, the same patterns can be used to create a authentication flow with any backend system. Hopefully you learned something, if not sorry this was so long.