can-connect icon indicating copy to clipboard operation
can-connect copied to clipboard

Enable modification of existing behavior chains

Open nlundquist opened this issue 8 years ago • 9 comments

Goals:

  • allow modification of existing can-connect behavior chains (via insertion and replacement)

API:

  • newBehaviour.insertAfter(existingBehaviour, behaviourChain) where existingBehaviour is a 'behaviorName' string or behaviour mixin instance matching an existing behaviour in the prototype chain. .insertAfter returns a new connection with the modification made. eg.
import superMap from 'can-connect/can/super-map/';
import newBehaviour from './custom-behaviour/';
var connection = superMap(...);
connection = newBehaviour.insertAfter('data/callbacks', newBehaviour);
  • newBehaviour.replace(existingBehaviour, behaviourChain) where existingBehaviour is a 'behaviorName' string or behaviour mixin instance matching an existing behaviour in the prototype chain. .replace returns a new connection with the modification made. eg.
import superMap from 'can-connect/can/super-map/';
import newBehaviour from './custom-behaviour/';
import dataCallbacks from 'can-connect/data/callbacks/';
var connection = superMap(...);
connection = newBehaviour.replace(dataCallbacks, newBehaviour);

nlundquist avatar May 10 '17 04:05 nlundquist

This feels wrong to me, you should really be creating new connections rather than modifying an existing one. What is the use case to have a connection that gets modified later?

matthewp avatar May 10 '17 14:05 matthewp

@matthewp my use case was the ability to use the predefined behaviour chain of can-connect/can/super-map with a replacement or additional behaviour without having to redefine the entire chain. However this could be accomplished by exposing the list of behaviours attached by superMap, creating a clone of superMap and then modifying the now-exposed list of behaviours directly.

Perhaps @justinbmeyer had another use case in mind where that might not be an acceptable solution?

nlundquist avatar May 10 '17 17:05 nlundquist

@matthewcp yes, people asked for mixins that could be added to an existing connection. This would aid in that.

justinbmeyer avatar May 24 '17 22:05 justinbmeyer

thanks for the clarification

nlundquist avatar May 24 '17 23:05 nlundquist

@justinbmeyer I understand that people are asking for it. They are asking for it because creating your own connections is too hard. The solution is make creating connections not hard any more, not add helper methods so people can use superMap and insert stuff in the middle.

matthewp avatar May 24 '17 23:05 matthewp

Why, that makes it easy. It's easy to understand a certain set of functionality and then add stuff to it. Starting with a base model, like baseMap is really convenient .

Sent from my iPhone

On May 24, 2017, at 6:34 PM, Matthew Phillips [email protected] wrote:

@justinbmeyer I understand that people are asking for it. They are asking for it because creating your own connections is too hard. The solution is make creating connections not hard any more, not add helper methods so people can use superMap and insert stuff in the middle.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

justinbmeyer avatar May 25 '17 00:05 justinbmeyer

@matthewp (now that I'm back to my computer, a more thoughtful response)

I think I'm acknowledging that creating even a custom base connection would be rather difficult even with can-validate-interface. A basic CanJS connection looks like:

var connection = canMap( constructor( dataUrl( baseBehavior(options) ) ) );

base-map would look like:

var connection = callbacksOnce( realTime( dataParse( dataCallbacks( constructorStore( canRef( canMap( constructor( dataUrl( baseBehavior(options) ) ) ) ) ) ) ) ) );

The solution is make creating connections not hard any more, not add helper methods so people can use superMap and insert stuff in the middle.

The interface stuff and documentation improvements are designed to directly help making piece-by-piece connections. We are also open to other suggestions that would improve this specifically (I'm not aware of alternatives that don't break existing APIs). Even if there are other good suggestions, it doesn't mean this isn't a valid and useful suggestion. This isn't an either-or situation. It's a yes-and.

Fortunately, this can make creating your own connections easy. I can create a "simpleMap" behavior that makes sure canMap, constructor, and dataUrl are all added like:

var someBaseConnection = base({ ... });
var mapConnection = addSimpleMap( someBaseConnection )

If someone wants real-time, it can add constructorStore, realTime, callbacksOnce like:

var connection = addRealTime( mapConnection )

This functionality allows behaviors that mixin several behaviors at once ... collections of behaviors.

@bmomberger-bitovi wanted to make something like real-time automatically add constructorStore and callbacksOnce, but this broke the independence of these behaviors. I think it's important that someone can make a different constructorStore.

This functionality allows mixins that provide a bunch of other behaviors, ensure that the right mixins are present and add them if not.

justinbmeyer avatar May 25 '17 00:05 justinbmeyer

I'm cool with this as long as these "middle level" mixins are created. I believe an end user shouldn't have to choose between high-level things like superMap and super low-level things like data/callbacks. You should be able to build your own connection without knowing about data/callbacks.

What are the mid-level mixins that are needed? I'll create issues for those.

matthewp avatar Jun 01 '17 11:06 matthewp

I've added my notes from the most recent contributors meeting where this was discussed to a gist.

nlundquist avatar Jun 02 '17 18:06 nlundquist