BorisMoore / jsviews

Interactive data-driven views, MVVM and MVP, built on top of JsRender templates
http://www.jsviews.com/#jsviews
MIT License
857 stars 130 forks source link

Using jsviews with other libraries - example: Google Maps #297

Closed Choran66 closed 9 years ago

Choran66 commented 9 years ago

Is it possible to create an extension tag for jsviews that will manage a complex object?

I would like to be able to write something like this:

{^{for locations}}
    {^{googlemap height='200px' /}} 
{{/for}}

Where the googlemap tag emits the required html, and can hook event handlers for when/if the user updates the location's address...What would the implmentation of "googlemap" look like, if it is even possible?

BorisMoore commented 9 years ago

Yes, that is totally possible.

You can create a custom 'tag control' - {{googleMap ...}}.

See:

Here is an example of how you can do it:

http://jsfiddle.net/BorisMoore/tzgef0w3/

Note that {^{googleMap ^latitude=lat ^longitude=lng ^zoom=zoom width="300px" height="200px"/}} uses the notation ^latitude=lat rather than latitude=lat for those tag properties which use live data-linking - so when the user updates the corresponding input the data-binding automatically updates the tag control. The onUpdate and onAfterLink handlers will also fire, so you can add code to further control the data-binding.

{^{for locations}}
    {^{googleMap ^latitude=lat ^longitude=lng ^zoom=zoom width="300px" height="200px"/}}
    Zoom: <input data-link="zoom" /><br/>
    Latitude: <input data-link="lat" /><br/>
    Longitude: <input data-link="lng" /><br/>
{{/for}}
$.views.tags({
    googleMap: {
        template: "<div class='map' style='\
                        width:{{:~tag.tagCtx.props.width}};\
                        height:{{:~tag.tagCtx.props.height}};\
                    '></div>",
        onUpdate: function(ev, eventArgs, tagCtxs) {
            return false; 
            // return false so as not to re-render every time.
        },
        onAfterLink: function(tagCtx, linkCtx) {
            var tag = this,
                props = tagCtx.props,
                options = {
                    center: {
                        lat: +props.latitude,
                        lng: +props.longitude
                    },
                    zoom: parseInt(props.zoom) || 0
                };

            if (tag.map) {
                // Update options changed by user
                tag.map.setOptions(options);
            } else {
                // Render google map in the div rendered by the template
                tag.map = new google.maps.Map(tag.contents("div")[0], options);
            }
        }
    }
});
model = {
    locations: [
        {lat: 37.7831, lng: -122.4039, zoom: 12},
        {lat: -33.8678, lng: 151.2073, zoom: 8}
    ]
};

And here is a more powerful example which shows direct two-way binding between the googleMap tag control and the underlying data, (so if you drag the map the underlying data tracks the center) and two-way binding between a slider tag control (using jQuery UI) and the zoom of the map instance. This one does not involve underlying data. The slider binds directly to the googleMap tag control instance.

http://jsfiddle.net/BorisMoore/uc7drf2v/

{^{for locations}}
    {^{googleMap lat lng zoom=12 width="300px" height="200px"/}}
    Zoom: <div data-link="{slider #childTags('googleMap')[0].zoom range='min' min=3 max=20 width=300}"></div><br/>
    Latitude: <input data-link="lat" /><br/>
    Longitude: <input data-link="lng" /><br/>
{{/for}}
Choran66 commented 9 years ago

Thanks so much Boris,

It always helps (me at least :D) to see a meaty realistic example :D

BorisMoore commented 9 years ago

I have added additional samples - see updated content above - and link to a new jsfiddle showing two-way binding between a jQuery UI tag control and a Google Map tag control.

Choran66 commented 9 years ago

I saw it and managed to adapt it to my needs...now I have four more to write :dart:

BorisMoore commented 9 years ago

OK - it may have changed since you looked. See http://jsfiddle.net/BorisMoore/uc7drf2v/. You can drag the map to change the underlying data, etc...

Choran66 commented 9 years ago

That goes beyond my needs...but is very cool [?]

On Sun, Feb 1, 2015 at 10:44 PM, Boris Moore notifications@github.com wrote:

OK - it may have changed since you looked. See http://jsfiddle.net/BorisMoore/uc7drf2v/. You can drag the map to change the underlying data, etc...

— Reply to this email directly or view it on GitHub https://github.com/BorisMoore/jsviews/issues/297#issuecomment-72402885.