2

When I google "Knockout Google Maps" I find quite some KO-based Google Maps implementations. All of which I was able to find take the approach to use a custom binding handler whereas I originally intended to implement it as a Knockout component.

Examples:

Can anyone point me in the right direction why one would prefer a custom binding handler over a KO component here?

My planned use case is this:

I'm implementing a page with a list of address search results. The list so far is a KO component, each list entry is generated by another KO component which the list component repeatedly calls in a foreach binding. Next to this list of search results I need a google map showing the result entries also in the map. There will also be quite a lot of interaction between the list, the list entries and the map.

Here's what I've got so far:

var GMap = function () {
    var self = this;

    var initMap = function() {
        var map = new google.maps.Map(document.getElementById('map'), {
            zoom: 13,
            center: {lat: 51.4387974, lng: 6.9922915}
        });
    };
  
    initMap();
};
$(document).ready(function() {
  ko.components.register('gmap', {
    viewModel: GMap,
    template: { element: 'gmap' }
  });
  ko.applyBindings();
});
#map {
  height: 400px;
  width: 600px;
}
<script src="https://maps.googleapis.com/maps/api/js?v=3.22"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<gmap></gmap>
<template id="gmap">
  <div id="map"></div>
</template>
connexo
  • 53,704
  • 14
  • 91
  • 128
  • 2
    Why do you want to use a component? What do you expect from the component that the binding handler doesn't offer you? Do you really know what a custom binding and a ko component are? If you make a concrete question like "I want to use a component instead of a custom binding because XXX" will can give you a good answer. As it's stated your question make no sense. – JotaBe Jan 07 '16 at 10:46
  • @JotaBe You said what was in my head more eloquently than I managed. Another reason they might be handlers rather than components, I see the one on github dates from at least a couple of years ago - when were components actually introduced? Could well have been after that? – James Thorpe Jan 07 '16 at 10:49
  • @JotaBe You ask exactly the type of questions that I need answers for. What are the advantages / downsides of either way? Why would one decide to go either way? – connexo Jan 07 '16 at 10:51
  • Code example working now. I also added an explanantion of my use case which hopefully helps you to point me in the right direction. – connexo Jan 07 '16 at 11:05
  • @JamesThorpe Components were introduced in 3.2.0, about 1 1/2 years ago, so in that case your assumption is probably right. So you personally don't see any advantages/disadvantages of either approach? – connexo Jan 07 '16 at 11:10
  • Right now I'm not sure. I think it may depend on exactly how you're passing data across from one to the other. Whilst I'm aware of the components in knockout, I haven't used them heavily yet. I have however written a number of binding handlers, and since I don't see any reason why I'd use a component here (ie what does it give me that a straight handler doesn't), I'd probably keep using a handler. – James Thorpe Jan 07 '16 at 11:13
  • For exactly the same reasons I decided to use a component here. And since I'm just about as unsure as you are, I'm asking potentially more experienced developers here. – connexo Jan 07 '16 at 11:14

2 Answers2

6

A component and a custom handler are completely different things.

Custom binding

Basically a custom binding have access to:

  • the HTML component where it's used
  • the bound value (expression supplied to the binding)
  • all the other bindings in the element
  • the binding context of the element, from which you can acces to $root, $parent, and so on

Its definition includes two functions:

  • init: that allows to do the initial setup, like initializing widgets, setting event handlers and so on
  • update: it's called after init. In that moment you can access properties (including observable properties) through the binding, all the element bindings, the context and so on. This creates subscriptios that will call update when any of the accessed observable changes.

So a custom binding shuld be used when you need to interact directly with the DOM element, for example to modify its properties, initialize widgets, subscribe to events and so on

Component

A component is completely different. When you define a componente you must define:

  • a template, which is a set of DOM elements, usually with bindings
  • a viewmodel (usually a constructor or a factory)

When you use the component:

  • the viewmodel is instanced
  • the template is loaded
  • the viewmodel is bound to the template

So, a componente allows to reuse viewmodels and templates

So, what's the difference?

A custom binding has direct access to the DOM elements, allowing to interact with them, subscribe to events, modify properties, and so on

A component is only a viewmodel, and a set of DOM elements with bindings to that particular viewmodel.

So, in the case of Google Maps, which needs to initialize a widget (the map) and interact with Map events, and respond to observable propèrties cahnges, you could never use a component, because the component doesn't allow the direct interaction with the DOM elements. (Remember is a bunch of HTML elements with bindings, and the corrresponding view model, whic can't include any logic to intercat with those elements).

A custom binding usually applies to a single element (althoug it could handle its children, like foreach). In the case of Google Maps you only need the element in which you'll show the map.

A component is usually a more or less complex set of DOM elements, which are not accesible "from the outside". The only communication with the main viewmodel is done through parameters. The component cannot directly interact with the DOM elements: it must do it via ko bindings.

So, for the case of Google Maps is clear that you need a custom binding.

It only makes sense to create a component when you want to modularize or reuse a set of DOM elements, and the related viewmodel, which can also include functionality like accessing web services (via AJAX), making computations (propbaly by using computed observables), and so on. For example, a shopping cart could be implemented using a component, which would include:

  • the DOM elements to show the items in the cart (probably an HTML table, and some controls)
  • controls to modify the cart content (for example for deleting elements, or changing quantities)
  • a viewmodel that show the total, the taxes and so on
  • functionality to store the cart for later, or pay for it (which could be ajax calls to services)

In this case the cart would have a viewmodel which would include the computed observables (to show the total and taxes), the functionality to remove items, or modify quantities, or store or pay, and so on. And a concrete set of DOM elements with bindings for this viewmodel, i.e. the HTML to show the cart and interact with it.

In the case of Google Maps a component could not be used without the help of a custom binding or with the hacky use of additional, non ko, scripts.

If you wanted to show a list of places beside a map, and modify that list, you could use a component, which would include a viewmodel with the list and related functionality, and a template including an element with the Google Maps custom binding. That would make sense: viewmodel + several elements.

Conclusion

This all means that a custom binding usually have a deep interaction with the bound DOM element, while a component has a higher level interaction with the elements, which must be done through bindings.

So, they play a role at a very different level. You cannot compare or interchange them.

If you insist on doing so, you could create a beast of a binding which behaves like a component, becasue you have full control on the elements, and full acces to the view model, but that's harder to implement than a component. And probably could do the other way round also in some esoteric way.

Community
  • 1
  • 1
JotaBe
  • 38,030
  • 8
  • 98
  • 117
  • Thanks for your detailed answer. Some examples of interaction: clicking on the list entry highlights the marker in the map. Clicking again opens a medium sized layer next to the marker with more detailed entry information. Moving the map causes a new ajax search request which will result in a new list of results. Clicking on a marker will make the list scroll to the clicked entry. Above the list, there will be filter criteria which always cause a new ajax search request (filtering is never done client-side), and a new search result in turn causes the map to be re-drawn. How would u model this? – connexo Jan 07 '16 at 13:43
  • 1
    @connexo Please, when you make a question and get a satisfactory answer, if you find new or more specific problems, instead of changing the question, keep it as is, and make a new question. My answer addressed the original question, which was basically "component vs custom binding", with Google Maps as example. Now I read the new edited question, and it has little to do with the answer. I wonder if you'd be so kind to edit this question so that the answer is reasonable, and make a new question. It's just a question of sanity, of keeping the Q&As useful for other people. That's what SO is about – JotaBe Jan 07 '16 at 16:27
  • I have not changed the question's essence at any point in time. I just tried to make myself clearer as of what I'm exactly asking, after your criticism of my question being too broad and not specific enough. I'm thankful for your answer - good answers to Knockout questions are rare on SO anyway - but what you are claiming now is just not true. – connexo Jan 07 '16 at 22:02
  • @connexo. Don't take it amiss. I've asked you respectfully to keep your question more similar to how it was originally for one reason: to keep it useful for the widest audience, which IMO is SO purpose. You can yourself see the original question in the edit history: "Can anyone point me in the right direction why one would prefer a custom binding handler over a KO component here?" and I've thoroughly answered it. That was the soul of the question, and now it's lost. You shoul keep an older edition of your question, and ask a new question to solve your new, much more specific problems. – JotaBe Jan 08 '16 at 09:00
1

Binding

Binding, a custom or not, is a very simple concept that covers 2 things:

  1. A property of a UI element changes, and thus it should update an object (ViewModel)
  2. A property of the object (ViewModel) changes, and thus it should update the UI element.

From the above if only 1 implemented, it is called One Way Binding (because if you change the UI, it will update the object but not the other way around). If both 1 and 2 are implemented, it is called Two Way Binding.

So at any time if you think you need something to do that, you would need to use binding, custom binding if the framework does not have the binding you need.

Most likely, the maps you speak of needed something like above. And it actually did because the author says this in the first paragraph:

Concretely, you can learn how to make the maps marker part of the View and automatically change its position any time when the ViewModel behind changes.

See, the author talks about 2 above: When the ViewModel changes, change the position of UI element.

Component

A component is a concept of having a reusable item that may have a UI but not necessarily, and all the code needed to make it work packaged along with it. This way it can be reused. For example, it may simply be an input UI element that only allows numbers. All the code needed for it is packaged along with the UI element.

Now the code packaged along with it may code related to bindings. It may even have custom bindings if the framework they used did not have the binding they needed. In addition it may have additional code that has nothing to do with binding.

Furthermore, a component may have a single UI element or multiple. A good example of a component with multiple elements would be a message box.

In Conclusion

Bindings and Components are separate things. A component may have bindings within it or it may have other code to make it work or both.

In the case of the maps you speak of, they have only added a feature to it: To react to changes in the ViewModel. It is not a component because it is not self contained and reusable.

They could have done it using a component. However, if they did that and said it is a KO component, it may still have KO specific binding code packaged with it along with the ViewModel and all the UI elements needed.

CodingYoshi
  • 25,467
  • 4
  • 62
  • 64