Comments (12)
You have to go through methods like you're talking about. So in your child iframe you might have something like this:
const childModel = {
max: 5000
};
const connection = Penpal.connectToParent({
methods: {
get(name) {
return childModel[name];
}
});
And then from the parent:
connection.promise.then(child => child.get('max').then(max => console.log(max)));
from penpal.
I like the configuration use case, such as using debug
to tell a child to operate in debug mode.
IMHO the most common mistake with @gajewsk2's proposal would be someone expects Penpal to create a proxy object instead of freezing the property.
var object = {};
object.debug: true;
object.getDebug: function(){ return object.debug; };
Penpal.connectToParent(object);
object.debug = false;
// Later
child.getDebug().then(debug => debug === child.debug) // Why aren't they equal?
child.debug.get().then(...) // OR! should we provide async getters for props so that mutations can go through
A couple suggestions here:
- Separate methods from metadata e.g
Penpal.connectToParent(methods,metadata)
. Would help clarify the difference between the static frozen properties and the dynamic methods. Access viaparent._metadata.debug
. - Use
Object.freeze
to freeze the properties.
** Aside **
For Parent->Child communication the fastest approach wouldn't used PostMessage at all, it would use query params or hash params. That way if you were trying to get the Client to debug, it would happen immediately instead of only after the handshake is complete. I'm not suggesting we do this, just reminding about speediness of passing configuration details.
from penpal.
Cool, gets the job done. Would it be possible to expose properties as well in a future update? Or does that go against Penpal's design somehow?
from penpal.
It kind of goes against the design. Penpal's primary goal is communication (for which methods are used). Whether you have data models or how you might structure them is outside of its scope.
Something that might be helpful to understand (if you don't already) is that the child object that you get here:
connection.promise.then(child => child.get('max').then(max => console.log(max)));
isn't any actual object that resides inside your iframe. Basically, when the iframe connects to the parent window, it collects any keys that are on the methods
object and passes them to the parent window. The parent window then reconstructs an object with the same keys and makes some proxy methods for their values. This object serves as a proxy and becomes your child
object in the snippet above. As such, child
isn't a "live" object. For example, if you add or remove properties (or changed their values) on the methods
object here:
const connection = Penpal.connectToParent({
methods: {
get(name) {
return childModel[name];
}
});
after connectToParent
has been called, the child
object that's in the parent wouldn't be updated.
Even though the concept of exposing properties is against the design, I'd still like to know more about how you're thinking such a mechanism would work. If you changed max
from the iframe, would you expect the new value to be sent to the parent window to update child.max
? If so, you may run into a race condition because iframe communication is asynchronous. In other words, if you tried to access child.max
from the parent window at about the same time max
is updated from within the iframe, you may not be getting the actual, current value that's been set from within the iframe.
from penpal.
My view of Penpal was as a more robust postmessage. I use postmessage to pass primitive or static configuration objects one way typically. I wouldn't expect the two way binding to persist for initial connection properties.
EDIT:
The interaction i'm talking about it only for properties from initial connections. I could use PostMate for something like that or just the builtin postmessage, just hoping for something more elegant.
from penpal.
You can pass primitive or static configuration objects back and forth. What I've shown in my original response is a pull methodology. If you want a push methodology (more like postMessage) rather than a pull, you can do so:
From the child:
connection.promise.then(parent => {
parent.onChildData(childData);
});
From the parent:
const connection = Penpal.connectToChild({
...
methods: {
onChildData(data) {
console.log('child data', data);
}
}
});
from penpal.
@gajewsk2 Do you have a proposal for what the API would look like in Penpal that would satisfy what you're looking for?
from penpal.
I'm thinking my ideal api would allow any property type and not have a methods property by default:
From Child
const connection = Penpal.connectToParent({
get: function(name) {
return childModel[name];
},
someMethod: function(blah){return foo;},
config:{
parentOrigin: '*',
debug: false,
promise: Promise
},
someObj: {
oneAndDone: 123,
iWontUpdateWithoutAnotherConnnection: 'default'
}
});
From Parent:
connection.promise.then(parent => {
// I've already gotten an initial response,
//according to the childs signature I can now access someObj syncronously
console.log(parent.someObj.oneAndDone);
// methods will continue with usual Penpal async style
parent.someMethod(parent.someObj).then((foo)=>console.log(foo));
});
I realize users could put methods inside of objects so to support them you would have to go through the nested objects and detect if their type is a function and then Penpal-ify it, but I think this sort of structure makes it feel like you are using objects in a very natural JS way.
from penpal.
Thoughts on this?
from penpal.
I'm interested in separating methods and metadata - I think it's a valid concern and thought. And I've personally never seen a valid justification of the speed impact for Object.freeze
, but that aside, it certainly would make it clear to the user.
To your side comment, I'm quite familiar with using query params on iframes for these sorts of things, but what do you mean by hash params in this context?
from penpal.
I have the same concerns that @loganvolkers expressed. I'm open to considering an extra metadata param (or something similar) so that it's more clear that the object is not going to be kept up to date after it's sent to other window. Using parent._metadata
to access it feels quirky. I don't really like any of the alternatives I can think of either though.
I'd be curious to hear about use cases (other than debug
) that this metadata would be useful for where the current design doesn't work well. In my usage, I've just sent initial metadata in a call right after the connection is established. Something like:
connection.promise.then(child => {
child.setMetadata(someMetadata);
});
from penpal.
At the moment, I'm not convinced that the value this would bring to the library would outweigh the cost of a more complex API. Closing.
from penpal.
Related Issues (20)
- Compatibility v4-v5 HOT 2
- Latest chrome update breaks the penpal HOT 2
- TypeScript imports with Penpal 5.2.0 HOT 6
- Serializing Objects with Functions causes an error HOT 4
- Provide typing for Connection HOT 1
- How to detect if connection with child was lost? HOT 11
- Option to skip iframe validation? HOT 6
- Remove check that determines if `connectToParent` is running inside iframe HOT 1
- Iframe Removal Monitoring not Working with Custom Elements HOT 7
- Export types HOT 6
- Types for the response of Promise returned after connection established HOT 2
- dynamic iframe url HOT 3
- Make parentOrigin on connectToParent required
- Including penpal in babel producing errors HOT 1
- Examples for using with React Hooks HOT 4
- error "Cannot read properties of null (reading 'postMessage')" HOT 9
- Question: Why does penpal use Window#postMessage instead of MessageChannel? HOT 2
- connected fail HOT 2
- [Penpal] Parent: Awaiting handshake
- Feature request: allow subdomains of childOrigin HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from penpal.