WoowahanJS

repository·v1·Indexed 41 days ago

https://github.com/woowabros/woowahanjs

A web application framework for BackboneJS designed for large-scale projects. It focuses on decoupling UI from business logic using an Action & Reducer pattern inspired by Flux and Redux, featuring hierarchical view component management, one-way data binding, and specialized tools like CollectionView for rendering API data. Version 1.2.2.

Tokens
15.1K
Snippets
52
Records
62
Agent score
52%

What's inside WoowahanJS

  1. Overview of WoowahanJS

    v1

    WoowahanJS is a framework designed for developing large-scale web applications. It focuses on facilitating collaboration between publishers and programmers by providing an architecture that minimizes dependencies between UI and business logic.

    Key features include:

    • Hierarchical view component management.
    • One-way data binding for fast and productive UI work.
    • Architecture inspired by Flux and Redux for managing state flows triggered by API calls.

    It is built on top of BackboneJS, meaning UnderscoreJS and jQuery are available for use within the ecosystem.

  2. Explore WoowahanJS usage examples

    v1

    The examples directory contains various implementations demonstrating the core capabilities of WoowahanJS. You can use these examples to understand specific patterns such as data binding, routing, and component management.

    Key example types available:

    • Data Binding: See bind for one-way data binding implementations.
    • List Rendering: See listview for displaying collection data from an API server in a list view.
    • Global Components: See modal to learn how to register and use common view components (e.g., Bootstrap modals) across a web app.
    • Routing: See route for implementing routing within a Single Page Application (SPA) structure.
    • Data Validation: See schema to understand how to define action message structures and validate data.
    • Full Application Patterns: See todo for a WoowahanJS implementation of the TODO MVC specification to compare development patterns with other frameworks.
  3. What is a View Model in WoowahanJS

    v1

    A View Model is the state held by a view. The View Model is combined with the view's template to construct the UI.

    If a view needs to maintain state throughout its lifecycle, it is recommended to initialize that state within the initialize lifecycle method using this.setModel().

    Woowahan.View.create('MyView', {
      initialize() {
        this.setModel({
          title: 'User List'
        });
      }
    });
  4. How to get route paths from a View using getRouteTables

    v1

    Every View component has access to a this.getRouteTables method. This method allows you to retrieve the actual URL string associated with a specific View, including dynamic parameters and query strings. This is useful when a component needs to programmatically navigate to a specific route.

    To ensure reliable retrieval, it is recommended to use a routeName alias in your app.start configuration. If routeName is not provided, the method defaults to using the View name (the first argument passed to Woowahan.View.create).

    // Using the alias 'UsersView' defined in app.start
    this.getRouteTables('UsersView'); 
  5. Access DOM elements using Refs

    v1

    To avoid tight coupling between your view logic and your UI structure (like CSS class names), use the data-ref attribute in your templates. When an element has a data-ref attribute, it is automatically assigned to the this.refs object within your view, allowing you to access it reliably even if the underlying HTML structure or CSS classes change.

    Instead of using selector-based lookups like this.$el.find('.class-name'), use this.$(this.refs.refName).

    <div class="container">
        <div class="alert alert-success" role="alert" data-ref="alert">Message</div>
        <button type="button" class="btn btn-toggle">Toggle</button>
    </div>
    Woowahan.View.create('Foo', {
      template: Template,
      events: {
        'click .btn-toggle': 'onToggleElement'
      },
    
      onToggleElement(event) {
        // Access the element via this.refs instead of a CSS selector
        this.$(this.refs.alert).toggle();
      }
    });
  6. Understand the Action & Reducer pattern

    v1

    WoowahanJS uses the Action & Reducer pattern to separate UI code from state (data) and state management logic.

    • Action: Acts as a "key" that triggers a specific task. Actions have a 1:1 relationship with Reducers.
    • Reducer: A task processor that handles the logic associated with a specific Action. Reducers are responsible for side effects like API calls (XHR/Ajax).
    • Dispatch: The mechanism used to send an Action to a Reducer. It can be called from any View.
  7. Understand the View Lifecycle

    v1

    The View lifecycle follows this sequence: initialize $\rightarrow$ viewWillMount $\rightarrow$ rendering $\rightarrow$ viewDidMount $\rightarrow$ viewWillUnmount $\rightarrow$ remove.

    • initialize(): Runs once when the view is created. Use it for setup.
    • viewWillMount(renderData): Called before rendering. You can modify renderData (a copy of the model) to influence the final HTML. You must return renderData for changes to take effect. Modifying the model directly via this.setModel() inside this method will not reflect in the current render cycle.
    • viewDidMount($el): Called immediately after rendering and DOM loading. The argument $el is a jQuery object representing the view's DOM element.
    • viewWillUnmount(): Called before the view is removed.
    • remove(): Final stage of destruction.
    /* Correct way to modify data for rendering */
    viewWillMount(renderData) {
      renderData.name = `Hello, ${renderData.name}`;
      return renderData;
    }
    
    /* Correct way to use the DOM after mount */
    viewDidMount($el) {
      $el.find('.switch').toggleClass('on');
    }
  8. Communicate between Parent and Child views using @events

    v1

    To avoid tight coupling between parent and child views, use @event syntax. Instead of the parent listening to specific DOM selectors inside the child, the child dispatches a custom event, and the parent listens for that event name prefixed with @.

    1. In the Child View: Use this.dispatch(Woowahan.Event.create('eventName')) to broadcast an event.
    2. In the Parent View: Define the event in the events object using the @eventName syntax.

    If a parent has multiple child views in different containers, you can specify a selector to target a specific child: @eventName .selector.

    // Child View: Dispatches the event
    var childView = Woowahan.View.create('Child', {
      events: {
        'click .btn.btn-search': 'onSearch'
      },
      
      onSearch() {
        this.dispatch(Woowahan.Event.create('search'));
      }
    });
    
    // Parent View: Listens for the dispatched event
    var parentView = Woowahan.View.create('Parent', {
      events: {
        '@search': 'onSearch'
      },
        
      viewDidMount() {
        this.updateView('.search-form', childView);
      },
      
      onSearch() {
        // Triggered when childView dispatches 'search'
      }
    });
  9. Collect input data automatically with @events

    v1

    You can simplify event handlers by instructing the events configuration to automatically collect data from specific DOM selectors and pass them as arguments to the handler.

    • Single Selector: onSearch(input[name=keyword]) passes the value of the element matching the selector.
    • Multiple Selectors: onSearch(input[name=keyword], .search.option) passes multiple values.
    • Form Data: If the selector is a FORM (e.g., @submit .join-form), the handler receives the form object containing all its input data (e.g., form.name, form.password).

    Note: this.$el is a jQuery object representing the view's root element, allowing you to perform standard jQuery operations.

    // Example: Collecting multiple inputs via selectors
    var childView = Woowahan.View.create('Child', {
      events: {
        '@click .btn-search': 'onSearch(input[name=keyword], .search.option)'
      },
      
      onSearch(keyword, option) {
        // keyword and option are automatically extracted from the DOM
      }
    });
    
    // Example: Collecting all form data on submit
    var childView = Woowahan.View.create('Child', {
      events: {
        '@submit .join-form': 'onJoin()'
      },
      
      onJoin(form) {
        // form contains all sub-element data (e.g., form.username)
      }
    });
  10. Run the webpack-dev-server

    v1

    You can run the development server using the yarn run command, or by adding a start script to your package.json file.

    Option 1: Direct command

    $ yarn run webpack-dev-server

    Option 2: Using a package.json script Add the following to your package.json:

    "scripts": {
      "start": "webpack-dev-server"
    }

    Then run:

    $ yarn start

    Once the server is running, you can access the application at http://localhost:8080/.

  11. Configure a bundling project with Webpack and Babel

    v1

    For complex web applications requiring modular components, you can use WoowahanJS with a bundler. This allows you to use CommonJS or ES6 modules for component modularization. To ensure browser compatibility, you should use a transpilation process (such as Babel) and a bundler (such as Webpack).

    Refer to the examples directory for pre-configured setups using Webpack and Babel.

    /* Refer to the examples directory for Webpack/Babel configurations */