Giter VIP home page Giter VIP logo

ju-components's Introduction

Build Status

Ju-Components

This library can be used as a standalone library or as a separate dependencies library, in which case we will need to add the following entry to the require config file:

require.config({
    paths: {
        'ju-components' : 'lib/vendor/ju-components'
    }
});

about ju-components

Components are self contained blocks whose intention is to be easily reusable, modular and provide a common interface to interact with other components.

They're defined as a hierarchical set of objects, that handle resources (stylesheets, markup, translations, and options, contextual and configuration data), data and visual elements.

Here we provide some details about their life cycle, definition and a subset of the API.

component's definition

The most important elements are the resources, the children definition and the component's class definition itself.

resource map

{
    cssFile : [ list of css file paths ],
    l10n : [ list of l10n keys ],
    template : [ list of template paths ],
    optionsData : [ list of options data keys ],
    appConfig : [ list of app config keys ],
    context : { dictionary of handler_name => { handler options } }
}

children definition

{
    component : {
        component : 'path/to/a/component',
        insertionPoint : '.imASelector',
        opts : { component-dependent options }
    }
}

class definition

An implementation that inherits from BaseComponent class.

component's life cycle

init

Here you can set options and resource map.

load (insertionPoint, ...)

Should be called only in a root component (i.e. a component with no parent, automatically called on children components). It's the entry point to build a component. insertionPoint: an element where we'll insert the component. Anything jQuery can handle.

fetchChildrenComponents

Using the children definition, creates instances of all of them.

fetchResources

Performs a single request to retrieve the resources required by the whole component tree.

setup

After the resources are loaded, stores a $view reference, sets up some resources, caches the tags defined in this.S, automatically calls bindEvents and performs children set up. Implicit flow during setup:

  • this.$view is set
  • translateOptions is called
  • configureComponent is called (you should overwrite it and call appendToView to initialize view)
  • _findLocalElems is called (sets this.t with cached tags)
  • bindEvents is called (you should overwrite it for event binding)
  • childrenSetup is called
  • READY event is triggered
  • setupCompleted is called

setData

If the component includes capabilities to communicate with the server using a proxy (i.e. they extend from BaseWithProxy) they can retrieve a payload to load data into the component tree.

component's api I (data flow)

The most important methods are getData and setData. Both of them produce/consume an object that's mapped to the component hierarchy. In other words, for the following object:

{ name : { first_name : 'Satanás', last_name : 'Ramírez' }, identification : '333' }

And the following component definition in any root component:

{
    name : { component : 'somepath', insertionPoint : 'someInsertionPoint},
    identification : { component : 'somepath', insertionPoint : 'someInsertionPoint}
}

And the following children definition for name component:

{
    first_name : { component : 'somepath', insertionPoint : 'someInsertionPoint},
    last_name : { component : 'somepath', insertionPoint : 'someInsertionPoint}
}

We can rely in an implicit flow that will take advantage of the mapping to pass the data to the component whose key matches the data key. In other words, if we setData in the parent component of name and identification, the first_name and last_name data will be set into the components with the same name without any additional code.

The same happens for getData. The produced object will have the same structure as the one of the component tree, so we can have a payload ready to be passed to anybody expecting the same JSON data defined above.

Some important notes

  • You can define a this.S object with selectors. The keys will be mapped to a this.t object with the same keys defined in this.S but with a dollar sign at the beginning. (e.g. S = { view : '.view'} => t = {$view : jQuery object } )
  • Always prefer composition over inheritance when creating new components.
  • Always use templates when dynamic markup generation is required.
  • There are methods to manipulate the get/setData flow. Always try to keep the implicit flow unmodified unless you have to make data-specific operations (like in the case you have a component whose data shouldn't be get, so you override getData to prevent that to happen)

ju-components's People

Contributors

andreybs11 avatar canamo06 avatar jpgarbanzo avatar klam avatar sesegura avatar stevevega avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ju-components's Issues

List marked as changed on landing component destroy

When a landing component is destroy, list are marked as changed by default

  • LandingComponent.destroy()
  • List.destroy()
  • List.clear()
  • List.emptyList()
  • List.fireEventAndNotify(ListComponent.EV.CLEARED)
  • Save-Changes > Changes-Tracker.on(ListComponent.EV.CLEARED, modifiedHandler)
  • Changes-Tracker.fireEvent(ChangesTracker.EV.COMPONENT_CHANGED, changedComponent);

Configurable resource strategy

We currently support unified (all from resource server) and serverless srategies. There is no way to define combined strategies.

Main definitions

Create a reusable and extendable way to store common definitions like blocks (ie. ComponentDef)

Separate children definition from instantiation+view+dettach

Several main components are "hacking" the way of loading resources via children definition, but not including initially in view or as dettached elements (ie. list, timeline, multi-view). We should work a way of separating flows like having an option or flag to define if a child should be inserted automatically to the view or just load its resources on load.

Inmediate save strategy

Add a save strategy for supporting autosave on components
A custom tracker may be needed for listening custom application events

Save strategies customization and changes trackers

As we learn from the immediate save strategy added on v.1.0.4, any strategy should support an options for customizing the changes tracker (which in the end determines the events detected as "change")

Base with proxy and save shouldn't be part of classes hierarchy

We are aware of known issues happening because the proxy and save were attached as part of components classes hierarchy (from BaseComponent) instead of using composition

Known issues

  • Landing components can't detect emptiness state
  • Proxy or save can't be added to any level of the components tree, so they were always required at root component of view

Suggested solution:
Create the concept of flows which are managed by handlers. This will let us separate proxy (will be known as 'fetch-flow') and save-flow to be compose into any component class definition

Payload confusion

The Request Payload - or to be more precise: payload body of a HTTP Request - is the data normally send by a POST or PUT Request. It's the part after the headers and the CRLF of a HTTP Request.
Source: http://stackoverflow.com/questions/23118249/whats-the-difference-between-request-payload-vs-form-data-as-seen-in-chrome

There is several methods (getComponentPayload, getPayload, others) which were named as if they were meant to compose ajax payload data, but instead they are used for calling a proxy. Lets review some naming conventions to make those methods more significant.

Suggestion:

  • Separate response, proxy and payload as handlers for all requests
  • Use correct naming as "fetch" , "fetchDataFromServer"

Options handling

There should be a way to reuse options handling as a composition of any class

  • setOptions
  • optionsPrepare
  • optionsCollector

Children definitions

We are seeing problems on children definition assignments

this.childrenDef = CHILDREN_DEFINITION;

This is bad! :( A direct reference is stored from childrenDef to CHILDREN_DEFINITION which is then passed to binders or class methods meaning the original definition is changed directly between instances. We should provide some standard setter method (hide inner implementation) and safe assign a clone of the provided definition.

this.setChildrenDefinition(CHILDREN_DEFINITION)
setChildrenDefinition : function(childrenDef){ this.childrenDef = $.extend(true, {}, childrenDef); }

Allow the UI handler to capture an error in save flow

When an error occurs during a save flow, we may want to either handle it in a custom way, using meaningful UI feedback, or let if fall back to a default handler, producing an unpredictable result.

However, even when the UI properly handled the save error, there wasn't a way to tell the save flow to stop there and don't call the default handler.

A way to handle this situation better is provided in PR #39

Options data storage

Work to do:

  • Remove huli keys
  • Provided CRUD methods for storage management
  • Mockup options data on serverless strategy

Optimize the Context Loader for same payload in components

When requesting the same data for two components I want to ask for the data to the server only once so I can reduce unnecessary load.

Requests such as
"context": { "historic_pathologies": { "36b21ccb-567f-4740-a498-b8b8b174c6ab": { "id_user": 17 }, "66ee6d17-1343-4ae3-b7c3-66fe4475d41e": { "id_user": 17 } } }

Can be further optimized by grouping the ids with the same payload.

Remove vendor dependencies

Ju-components should not depende on external libraries as:
bower.json
"dependencies": {
....
"x-editable": "1.5.1", ---> x-editable and select2 library
"mustache.js": ">=2.2.0", -----> render engine
"dropzone": ">=4.2.0" -----> uploader
},

Set data flow on list block

  • setData does not respect data and extraParentData parameters order
  • setData does not support custom params after second argument and bypass it to setChildrenData- > addChild -> ....
  • Editable is not fully separated

Add support for data preparation with promises on save

We currently support only data preparation through a callback function pass by parameters to the save data binder.

this.saveDataBehavior = new SaveDataBinder({
component : this,
saveProxyCallback : $.proxy(proxy.save, proxy),
prepareDataToSave : this._prepareDataForRequest,
onComponentSaveSuccess : $.proxy(this._onSaveSuccess, this),
onComponentSaveError : $.noop
});

Certain scenarios may require a data preparation with promises like: third party services requesting a token/approval...

Children loader

Ju-components doesn't currently provide a standard dynamic children loader helper. From setChildrenDefinition (v.1.0.3) and project experiences, we learn that it is very useful to have a loader which can be customize to support permissions, flag and other checks to help on initChildrenDef task.

@see base-with-children-loader

Objects extending and cloning

Object extending and cloning are currently handle by jQuery.extend()
We should keep in mind removing jQuery dependency and avoid the ambiguous usage of $.extend

Sounds to me like a good idea to have a "Ju" global object (similar to jQuery) to easily access utilities like this.

Insertion point deletion

If a component is merged with its view on appendToView, and later it's destroyed, the whole insertion point is removed from the DOM, which may cause problems whenever it has to be re-inserted.

Root delete

As root-append works on any root component when initializing, same behaviors should be work for on destroy. It should support deletion of a portion of the components tree or specific children.

Concerns:

  • Memory management
  • Dettach/reattach handling
  • Backbone reference and listeners

Known issue:

  • DOM stored data (ie jQuery.data) is deleted when calling jQuery.remove (vendor conflicts)
    Reproduce : list component > destroy > clear > child.destroy() [.remove()] > cascadeStateChange() > checkEmptiness() > getData() > vendor conflict [.data() is missing due to remove()]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.