Tinderbox Forum

OnRemove when moving Note from Container


(Ralph Alvy) #1

Suppose I have an “Archive” Container with the following settings:

Action: $Archived=True
OnRemove: $Archived=False

When I drag a Note into that Container, it assigns True to that Note. But when I drag a Note out of that Container, I see $Archive remains True. Is this because the Note’s $Archive was previously set, so the Container OnRemove event cannot touch that Attribute?


(Mark Anderson) #2

OnRemove is actually working. The problem lies in your code. In Tinderbox, Boolean data-type values are true and false and are case-sensitive. Thus your values of True and False won’t work as expected.

Due to coercion, any value other than false, a 0 (number zero) or a "" (an empty string), when passed into a Boolean attribute will coerce to true. Thus your OnRemove code:

$Archived=False

…sets a value of true!

So the correct actions are OnAdd:

$Archived=true;

OnRemove, either:

$Archived=false;

Or to reset to the default (false for Booleans**) value:

$Archived=;

** unless, of course you’ve set the doc default for the attribute to true. Otherwise, all new User Booleans and most System Booleans have a default of false. Some System ones use true where an attribute was added and the existing behaviour being controlled (and/or attribute name) made a true value a more intuitive default.


(Ralph Alvy) #3

Very clear, Mark. Thanks.


(Ralph Alvy) #4

One more twist on this. I’d like the following to be true:

  1. When I add a Note to the Archive Container or any of its subContainers, $Archived=true.

  2. When I remove a Note from the Archive Container or any of its subContainers, $Archived=false

Don’t I need an Agent for this?


(Ralph Alvy) #5

I forgot to mention what I’ve tried for this. I tried a Prototype that would be added to any Archive Container item, and that worked okay for assigning true to $Archived for each added item, but the OnRemove event of that Prototype didn’t fire when I dragged an item out of a subContainer there.


(Ralph Alvy) #6

Okay. I did it. I created a Proptotype “pArchiveEntry”. It applies itself to any Note added to it as a Container. Here’s the Action tab of both the Archive Container and Prototype “pArchiveEntry”:

$Prototype="pArchiveEntry";
$Archived=true;
$KeyAttributes=($KeyAttributes + "Archived");

And here’s the OnRemove tab of both the Archive Container and Prototype “pArchiveEntry”:

$Archived=false;

Now all descendants of the Archive Container get $Archived=true and lose that attribute when dragged out of the Archive Container or any of its descendant Containers.


(Paul Walters) #7

It is interesting that that works. I would have to parse why it does. Adding an Action and a Remove to the Prototype (which never, normally, has children – is not, normally, a container) would not cause any result other than that the notes who have that Prototype assigned also inherit the Action and Remove actions.

So, assigning a prototype to a note does not cause Action (or Remove for that matter) to do anything to the assignee notes.

Not sure why putting Action and Remove actions into a prototype does anything in particular.


(Mark Anderson) #8

$OnAdd and $OnRemove, aren’t intrinsic, so if set in a prototype those actions are inherited by any notes using the prototype.

He only bit I don’t get in the solution is the setting of $KeyAttributes as it breaks inheritance of KAs, which is generally useful. However, if notes with differing (and already locally set) KAs are being archived, then the code does make perfect sense.


(Paul Walters) #9

I know and understand all that, but the real question is: what does having an $OnAdd and $OnRemove in a note’s prototype have to do with solving the “toggling the ‘archived’ boolean” problem? $OnAdd and $OnRemoved are not triggered until a note gets a child. Inheriting $OnAdd and $OnRemove from a prototype does not cause them to operate on the note itself.

Something else is going on, not yet documented.


(Mark Anderson) #10

Thanks for the clarification. I see the missing bit. If the top container (that doesn’t use a prototype) lacks the OnRemove, then prototyped notes removed from it will not have their flag reset. However, any nested prototyped notes do currently unset the flag due to their inherited OnAdd. I assumed this was the OPs intent and that only nested archive notes would unset their flag if moved.

If it were my need/project, I’d make a prototype ‘A’ for the ‘top’ container(s)—which currently isn’t proposed, and then base the above prototype ‘B’ on that, with changes as necessary - e.g. the top container(s) might have different KAs, colours, badge, etc. By basing the archived notes’ prototype B on that used for the top container(s) A, it makes it easy to alter things like Add/Remove action by just editing prototype A, and have B inherit those changes. Thus is a the power of prototypes.

Have I understood correctly?


(Paul Walters) #11

You do, but my question is general and really has nothing to do with the OP’s request or solutions, or even with this whole thread.

My question is, restated yet another way again: “Why would a note want to inherit $OnAdd and/or $OnRemove from a prototype if that note never has children? $OnAdd and $OnRemove do nothing until that note is given children.”


(Mark Anderson) #12

Ah - a new and different. The OP’s question didn’t preclude nested items, therefore it was logical to assume they might occur. Anyway,…

However, the nested archival case shows a valid case for inherited $OnAdd and $OnRemove values. If a note inherits code for those via a prototype but has no children itself, the code is never invoked and no harm occurs. Indeed, if the prototype was intended for notes that were never intended to have children, then one would simply not set $OnAdd and $OnRemove values and a default (nil) value would be inherited - i.e. no code set.

So what upside would occur by changing the app to make the $OnAdd and $OnRemove attributes intrinsic (i.e. non-inheriting)?


(Paul Walters) #13

No, that’s not my question at all. I’ve hijacked @ralvy’s thread too much, and I’m not making myself clear, so let’s drop the discussion.


(Ralph Alvy) #14

Exactly. I wanted to make sure that all descendants, no matter how deeply nested within the Archive Container, had $OnAdd and $OnRemove active.


(Ralph Alvy) #15

This seems more elegant and I’ll try it.


(Ralph Alvy) #16

That’s exactly what’s happening.


(Mark Anderson) #17

Thanks for sharing that, as it is a useful confirmation for later readers.


(Ralph Alvy) #18

In the Archive Container will be various Containers like Code, Task, Projects, etc. Stuff I really don’t need to see anymore, but stored just in case. And each of those Containers can have subContainers.

But one thing I notice is that Cutting a Note to the Clipboard doesn’t activate its Container’s OnRemove event. I thought it would be easy to just Cut a Note and then Paste it to the Archive Container. But now I see I need to Drag it there to take advantage of the OnRemove event.


(Mark Anderson) #19

From a user’s perspective, it would make sense that any removal (action code, drag drop, cut, etc. should work). I can see ‘cut’ is interesting edge case as as the process may act slightly differently under the hood than assumed. For instance, take a copy to paste board, delete original in which case there’s no removal.

Another possible edge case. When an alias no longer matching the query is deleted from an agent, does the agent’s OnRemove fire? I’ve not tested explicitly. I’d assume it would as an object, albeit an alias, is being ‘removed’ but might simply be seen as being deleted.

Flagging for @eastgate.


(eastgate) #20

OnRemove does fire when a note is cut or deleted.

Two things to keep in mind:

  • this is bound to the note that is about to be deleted.
  • The OnRemove action is called before the note is deleted.

Also, the OnRemove action that fires is the container’s OnRemove, just as adding a note to a container fires the container’s OnAdd action.