HTML Image Element

Lotus Image Element

Here are examples of lotus image component. The x-lotus-image tag extends the Lotus.LotusHTMLElement tag. Our x-lotus-image is also mapped to a Lotus component in the call to context.componentMap.mapComponent('x-lotus-image', Lotus.LotusHTMLElement.prototype, Lotus.Image, xtag);.A new instance of Lotus.Image is attached to each tag instance. Use the select list to change the image source. Observe the loading icon that is displayed. If images become cached or loads too quickly open your dev tools and turn on throttling. Images will be sized according the skin's data-attribute-thumb-width and data-attribute-thumb-height attributes. The control will set the max width and height of the image based on a scaling algorithm that preserves aspect ratio.

We also implement two way data binding in this example as a means to keep all the selected list items in sync with each other. See the code below for a complete explination of data binding in LotusJS.


Dynamically Change Skin

If your browser does not natively support web component (Safari) you will not see any change. See the xTag polyfill workaround below.

Changing the appearance of any image control instance is as simple as attaching a different skin using data-template-url="templates/image2.html". Below is the exact same custom set of tags with a different skin attached. All using the same set of selectors encapsulated with Shadow DOM. Imagine how many skins could be created without a single change to the component code.


xTag Pollyfill Workaround

Note: If your browser does not natively support web components you have to attach the new skin using a different tag. In this example we do the following: context.componentMap.mapComponent('x-lotus-image2', Lotus.LotusHTMLElement.prototype, Lotus.Image, xtag);. This is an issue with the xTag core and how it encapsulates styles using the tag name.


Mediating Components

The x-lotus-image tag exposes a single ready event by default. In order to listen for that event you have to assign an event handler after the document loads. An example is below. After the component is ready we can set it's model to change the image source. However if you are serious about event mediation of we encourage you to check out lotusjs-mvw. This is a full blown MVW framework which comes with a mediator map for your components (and much more). This allows you to build application mediators that are mapped to your custom tags. Mediators can do all sorts of useful things like triggering business logic, dispatching application events to trigger commands, and setting up data binding within your surrounding application.

		
        var context = (function (xtag) {
            var context = new Lotus.Context(new Lavender.Config);
            context.componentMap.mapComponent('x-lotus-image', Lotus.LotusHTMLElement.prototype, Lotus.Image, xtag);
            context.componentMap.mapComponent('x-lotus-image2', Lotus.LotusHTMLElement.prototype, Lotus.Image, xtag);
            context.componentMap.mapComponent('x-lotus-select', Lotus.LotusHTMLElement.prototype, Lotus.ListCollectionView, xtag);
            return context;
        }(xtag));
        //start binding source set up. This is a crude example. Most application should use a MVW framework like lotusjs-mwv set create data models and apply bindings using mediators.
        //below we create a source for data binding. Components should always effect an application model instead of acting on the view directly
        //you can then use two way data bindings on the model to keep your components in sync with model. Changes in the model are then resolved by the component.
        var BindingSource = function(){
            Lavender.Subject.prototype.constructor.call(this);
            var _selectedItem;
            var _collection = new Lavender.ArrayList();
            this.addProperties({
                selectedItem: {
                    get: function () {
                        return _selectedItem;
                    },
                    set: function (val) {
                        _selectedItem = val;
                        this.notify(val, "selectedItem");
                    }
                },
                collection: {
                    get: function () {
                        return _collection;
                    },
                    set: function (val) {
                        _collection = val;
                        this.notify(val, "collection");
                    }
                }
            });
            //set up pour collection
            this.collection.addItem({label: 'Sunset 1', value: 'assets/photos/Sunset_2007-1.jpg', src: 'assets/photos/Sunset_2007-1.jpg'});
            this.collection.addItem({label: 'Sunset 2', value: 'assets/photos/Sunset-socialphy.com_.jpg', src: 'assets/photos/Sunset-socialphy.com_.jpg'});
            this.collection.addItem({label: 'Sunset 3', value: 'assets/photos/sunset-birds1.jpg', src: 'assets/photos/sunset-birds1.jpg'});
            this.collection.addItem({label: 'Full Moon', value: 'assets/photos/FullMoon2010.jpg', src: 'assets/photos/FullMoon2010.jpg', selected:true});
            //set the selected item
            this.selectedItem = this.collection.getItemAt(0);

            BindingSource.prototype.setSelectedItemFromCollectionView = function(item){
                if(item && item.model != this.selectedItem ){
                    this.selectedItem = item.model;
                }
            }
        };
        //Lavender.ObjectUtils has some handy utility methods including extend which enbales prototypal inheritance between objects
        //Lavender.Subject exposes several useful methods including addProperties and notify which is part of an implmentation of the observable pattern
        Lavender.ObjectUtils.extend(Lavender.Subject, BindingSource);
        //end binding source set up
        //create an instance of our source
        var bindingSource = new BindingSource();
        //define our handler to set up the component when it loads.
        //Note you can avoid this if you use https://www.npmjs.com/package/lotusjs-mvw and take advantage of component mediators
        //mediators are attached to component instances at the moment of creation and receive callbacks for the ready evet automatically
        var handler={
            onReady:function(event){
                handler.initComponent(event.payload.target);
            },
            initComponent:function(component){
                //set the image source
                if(component instanceof Lotus.Image){
                    component.model = bindingSource.selectedItem;
                    //bind changes in the binding source's selected item attribute to our components model attribute
                    bindingSource.binder.bind(bindingSource, 'selectedItem', component, 'model');

                }else{
                    component.addEventListener(Lotus.InputEvent.CHANGE, handler, 'onChange');

                    component.collection = bindingSource.collection;
                    //set up a two way boindiong between the lists selected item and our binding source. This ensures all the lists stay in sync with the selected image
                    bindingSource.binder.bind(component, 'selectedItem', bindingSource, 'setSelectedItemFromCollectionView');
                    bindingSource.binder.bind(bindingSource, 'selectedItem', component, 'setSelectedItem');
                    bindingSource.setSelectedItemFromCollectionView(component.selectedItem);
                }
            },
            addEventListeners:function (component) {
                //Do not set up data providers until the component is ready!
                //if you use lotusjs-mvw you can take advantage of component mediators that have built in onReady callbacks
                if(!component.ready){
                    component.addEventListener(Lotus.ComponentEvent.READY, handler, 'onReady')
                }else{
                    handler.initComponent(component);
                }
            },
            onChange: function (event) {
                console.log('My callback function received value: ' + event.payload.target.selectedItem.model.value);
            }
        }
        //the following is an example of how you can mediate the component events that are dispatched.
        //A better alternative is to use https://www.npmjs.com/package/lotusjs-mvw and take advantage of component mediators
        window.onload = function () {

            var list = document.getElementsByTagName('x-lotus-image');
            for (var i = 0; i < list.length; i++) {
                handler.addEventListeners(list[i].lotusComponentInstance);
            }
            //set up work around for pollyfill issue with xTag core
            list = document.getElementsByTagName('x-lotus-image2');
            for (var i = 0; i < list.length; i++) {
                handler.addEventListeners(list[i].lotusComponentInstance);
            }
            list = document.getElementsByTagName('x-lotus-select');
            for (var i = 0; i < list.length; i++) {
                handler.addEventListeners(list[i].lotusComponentInstance);
            }
        };