-
-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Setting instance level attributes in Reflex as a way to set context data is a confusing API #122
Comments
Thank @dylanjw for opening a thoughtful issue. I agree that editing the documentation to become clearer is definitely a good first step. It should definitely be mentioned in clearer terms on the reflex section in the documentation. If you've got suggestions to where you would like to see it elsewhere I'm open to hear it. What I had done earlier is to exclude "protected variables" > https://github.com/jonathan-s/django-sockpuppet/blob/master/sockpuppet/consumer.py#L237, however I had missed to add With that out of the way it should become less confusing for a user, or would you still find it confusing? Perhaps @nerdoc or @DamnedScholar have some thoughts as well? |
What if I do think it makes sense to only pass variables under |
Making |
I'd like to make another argument in support of namespacing passed context variables. Extending the reflex class with new methods/attributes has the potential to be a breaking change for someone with conflicting variable names in their project. While moving over to using |
I can open a PR with some doc changes. |
That would be most welcome :) |
I would also be into making the changes as @DamnedScholar suggested, to see what those could look like and keep the discussion going. |
I don't know if I understood correctly. But this is one of the thins tat are unnecessarily complicated in Sockpuppet IMHO. First, at the template, you have to set the <a href="#"
data-reflex="click->CounterReflex#increment"
data-step="1"
data-count="{{ count }}"
>Increment {{ count }}</a> Why is the data-value needed in the first place? On the backend side, you need to reference from sockpuppet.reflex import Reflex
class CounterReflex(Reflex):
def increment(self):
self.count = (
int(self.element.dataset['count']) +
int(self.element.dataset['step'])
) It would be much more pythonic to write: from sockpuppet.reflex import Reflex
class CounterReflex(Reflex):
# define class variables here, which become automatically
# available as template context variables in the frontend
count = 0
step = 1
def increment(self):
self.count += self.step At the template, this would be <a href="#"
data-reflex="click->CounterReflex#increment"
>Increment {{ count }}</a> and with available parameters: <a href="#"
data-reflex="click->CounterReflex#increment(1)"
>Increment {{ count }}</a> def increment(self, step): or even dynamically: <a href="#"
data-reflex="click->CounterReflex#increment({{ step }})"
>Increment {{ count }}</a> class CounterReflex(Reflex):
count = 0
step = 1
def increment(self, inc):
# the "inc" param here in this case gets filled with the {{step}} variable again. Just to show a use case.
self.count += inc
if inc == 1:
self.step = 2
else:
self.step=1 E.g. Unicorn does it linke this, and it is MUCH simpler, and let's the user set instance variables of the class (here If I would design an API, I'd do it like this... So @dylanjw, if I understood correctly, this (instance variables are context variables?) is already the current behavior in SP and you would like to change it? |
The |
Ah ok, now I understand better. Using |
Im just concerned with the API for passing context variables from the Reflex class to the client. Getting data back from the client to the Reflex is a bit awkward, but is out of scope for the changes being proposed. This might really just come down to personal opinion on API design. It feels like the Reflex is mixing concerns by putting context variables to be sent to the client as instance attributes. The Reflex is acting as both an object representing a UI interaction and a special datatype for the template context. It feels weird as a user to make sure my instance methods don't clash with template context variables, and also have to work around having any instance variables I add not just internal to the working of the class/instance but also potentially passed to the client. Putting the context variables under |
@dylanjw Having slept on this I think the api that you describe makes sense and the arguments you make are sound. Ie class MyReflex(Reflex):
def update(self):
self.context.field = "data" It should be backwards compatible, so that we can remove the old behaviour in a major version. We should also leave a logging warning if the new api isn't used so that the developer is notified in the command prompt. |
Ok - I see this is clearly the better solution, and @dylanjw you're right it's a point of view - how API designing is preferred. In this case, as Reflexes always are in context of a whole view, I definitely opt for separation of context as well... ❤️ |
I've slept a few nights on this topic again, and something else occurred to me. self.context.field = "data" is great for the writing side of data access. But what about reading? I think this is very confusing as well. name = self.element["attribute"]["value"] BTW: according to the docs, the
which is totally confusing IMHO, and badly documented. In 99% of all cases I suppose that the user wants to access the "value" of the input field. the So my suggestion here is something else: Why can't SP provide a higher level API for data reading access? SP could bind e.g. the value to a value property: class MyReflex(Reflex):
def increment(self, step: int = 1):
name = self.element.value # shortcut for self.element["attributes"]["value"]
self.context.upper_name = name.upper() This would be an approach to get data more easily out of the elements. It's much more readable and pythonic. I could be something like this in the @property
def value(self):
return self.attributes["value"]
@property
def checked(self):
return self.attributes["checked"] |
That would totally work for me. However it's worth keeping in mind that you can add any attribute to html so doing it through properties as above is probably not the best solution. |
That's true. I didn't want to suggest replacing the low-level API with properties. It's just that e.g. |
Ah, and it's not necessary to do hardcoded properties. Could be a |
I think it would also be preferable to keep the api the same as javascript ie for an
That way it would be consistent. I would also say it would be good to keep this in two separate PRs for the person who takes this on. Just checking in @dylanjw, were you keen on creating a PR for the context. |
ok - but then there's the docs - ATM they are wrong IMHO, even for the current behaviour. as said, "The element property contains all of the Reflex controller's DOM element attributes as well as other properties like, tagName, checked and value.", This should (ATM) be: "The element property contains an Would be a very small, but important docs improvement, which costs much time for beginners (like me). |
commit 5a6b5781a792eda242ce7608314b19edaac78ee1 Merge: bf37de9 81a0fbf Author: Danilodum <[email protected]> Date: Fri Aug 20 14:42:31 2021 +0200 Merge branch 'master' of https://github.com/jonathan-s/django-sockpuppet into jonathan-s-master commit 81a0fbf Author: Jonathan Sundqvist <[email protected]> Date: Wed Aug 4 20:04:42 2021 +0200 Some Channel improvements (jonathan-s#139) - Allow channel methods to be chained - Improve the doc strings with updated docs from cable ready. - Allow keyword arguments for each method that will be used in options. commit 728eb9c Author: Jonathan Sundqvist <[email protected]> Date: Sat Jul 31 22:04:40 2021 +0200 Emit browser console error when a reflex can't be loaded (jonathan-s#138) commit 76144ed Author: Jonathan Sundqvist <[email protected]> Date: Sat Jul 31 16:31:17 2021 +0200 Create a clearer description of modifying context in a reflex commit 23f5bf4 Author: GitHub Actions <[email protected]> Date: Sat Jul 24 09:38:55 2021 +0000 [nodoc] Update Changelog commit bc86e10 Author: Jonathan Sundqvist <[email protected]> Date: Sat Jul 24 11:38:26 2021 +0200 Remove Channels 2.4 in CI (jonathan-s#134) Channels 2.4 is proving problematic in CI, and it's not worth the effort to maintain that. Sockpuppet should still work for channels 2.4, but given we don't run a CI for it we can't make any promises for it. commit 52e3209 Author: Jonathan Sundqvist <[email protected]> Date: Sat Jul 24 11:19:31 2021 +0200 Amend element description to be correct @nerdoc pointed out that the element documentation was wrong in jonathan-s#122, so this updates the documentation to the current behaviour. commit 695ee72 Author: GitHub Actions <[email protected]> Date: Mon Jul 19 19:48:15 2021 +0000 [nodoc] Update Changelog commit 153e5b0 Author: ciag00 <[email protected]> Date: Mon Jul 19 20:47:35 2021 +0100 Fixing running initial_sockpuppet in windows (fixes jonathan-s#106) (jonathan-s#132) commit 455c71a Author: GitHub Actions <[email protected]> Date: Wed Jul 14 06:39:11 2021 +0000 [nodoc] Update Changelog commit c8140ae Author: Jonathan Sundqvist <[email protected]> Date: Wed Jul 14 08:38:37 2021 +0200 CI for django 3.2 (jonathan-s#127) commit 86f649e Author: GitHub Actions <[email protected]> Date: Wed Jul 14 06:13:03 2021 +0000 [nodoc] Update Changelog commit 51adb6b Author: Jonathan Sundqvist <[email protected]> Date: Wed Jul 14 08:12:31 2021 +0200 Don't use exception, instead of figure out what view it is. (jonathan-s#124) Figuring out which view it is and adding the correct property to that view is better than trying to re-render the view itself. This should solve for django's generic views. It won't work for Django vanilla views package, but we can deal with this later if someone show interest for that. commit 09375f9 Author: GitHub Actions <[email protected]> Date: Wed Jul 14 05:59:07 2021 +0000 [nodoc] Update Changelog commit dc246ac Author: Jonathan Sundqvist <[email protected]> Date: Wed Jul 14 07:58:36 2021 +0200 Bump dependencies (jonathan-s#126) Bump ws from 6.2.1 to 6.2.2 Bump browserslist from 4.11.1 to 4.16.6 Bump hosted-git-info from 2.8.5 to 2.8.9 Bump lodash from 4.17.20 to 4.17.21 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 1cc3865 Author: GitHub Actions <[email protected]> Date: Tue Jul 13 20:57:56 2021 +0000 [nodoc] Update Changelog commit a65444e Author: Jonathan Sundqvist <[email protected]> Date: Tue Jul 13 22:57:23 2021 +0200 Make the code black (jonathan-s#125) commit 69047da Author: GitHub Actions <[email protected]> Date: Tue Jul 13 20:54:52 2021 +0000 [nodoc] Update Changelog commit c33e021 Author: Andros Fenollosa <[email protected]> Date: Tue Jul 13 22:54:19 2021 +0200 Minor fix (jonathan-s#121) commit 4b7bcd7 Author: GitHub Actions <[email protected]> Date: Tue Jul 13 19:33:10 2021 +0000 [nodoc] Update Changelog commit 2ff7fd4 Author: Christian González <[email protected]> Date: Tue Jul 13 21:32:38 2021 +0200 Making camelCase and PascalCase more robust (jonathan-s#87) * Use Django's newer path method instead of url * gitignore sockpuppet/static/ * improve test README + enable pytest as test suite * add camelcase/pascacase templatetags filters * lint: remove whitespace + unused impotr * lint: fix whitespace * fix double pascalizing Reflex classes * fix linter error, remove unused import * validate reflex_name and keep it clear during scaffolding lifecycle * use f strings instead of format * use wording of other code doc * fix li index in doc * remove gitignored static files * make camelcase function more robust it now preserves already camelcased strings * remove unused (commented out) tests commit 79cc9da Author: GitHub Actions <[email protected]> Date: Tue Jul 13 19:28:51 2021 +0000 [nodoc] Update Changelog commit 1639aa7 Author: Christian González <[email protected]> Date: Tue Jul 13 21:28:22 2021 +0200 extract/const isProd (jonathan-s#118) to satisfy ESLint
Feature Request
Background:
I want to start out by saying Im new to sockpuppet, but love this project. One thing though. I find setting instance level attributes in Reflexes as a way to update context data to be a confusing API
Related to issue #43, It would be nice to make the documentation more explicit that user added reflex attributes get propagated into the context data during refreshes.
I also find the existence of the
context
attribute in reflexes promotes this confusion. For myself and other uninitiated, settingcontext
in a reflex instance has surprising behavior:get_context_data
.Possible solutions
Editing the documentation to better explain the API for changing context data would be a first step. A further improvement could be made to the overall API in one of two ways:
context
"private" by prepending with a "_". Right now it looks like its part of the API and not something reserved for internal use.context
.becomes
I think option 2 is a better direction but it would be a breaking change. It would be ideal to release a minor version where context is pulled both from the context attribute and instance level attributes before phasing out the instance level attribute propagation in a major version.
Maybe I am confusing some of the intended API and behavior. Would love to hear others thoughts.
PR link
TBD
The text was updated successfully, but these errors were encountered: