Seeking guidance for OnAdd code

I’m trying to strengthen my understanding of OnAdd code, and more complex Tinderbox code, in general. Right now, I’m trying to understand how to construct OnAdd code for folders that I drag and drop into Tinderbox file, and contain notes. I would like the OnAdd code to execute the following two functions:

(1) select all the notes inside imported containers, and apply the following action code:

$Text=$Name;
$Name=$Text.words(11)

(2) apply a prototype based on the container’s file naming conventions – specifically its prefix (e.g., REN_ART_[date] for article; REN_DOC_[date] for document; REN_INT_[date] for interview).

Again, I’m still trying my hand at figuring out Tinderbox’s coding, so this is what I thought would work…

if($Container.contains("REN_ART")){
	$Prototype=pArticle
	};

if($Container.contains("REN_DOC")){
	$Prototype=pDocument
	};

if($Container.contains("REN_ART")){
	$Prototype=pInterview
	};
};

@MartinBoycott-Brown thought that I should be using $Name instead of $Container, and he could certainly be right. (***I ported this query from another post, and hope I haven’t violated forum protocol by doing so.)

I expect both sections of code need to prefaced with something, but I’m not sure what they’d require. Thanks for your help!

I consulted atbref on $Container and I note that it states:

“Lets Tinderbox actions and rules change the parent of a note, moving it to a new place within the document.”

I don’t think that is what you are trying to do …

I hope @mwra will come along and throw some light on the question :slight_smile:

1 Like

Ah. I didn’t catch that! Thank you for your help with that…

OnAdd doesn’t work by selecting things. Rather it runs once, and once only on any item (note or container note—but not a containers’s contents) that is created in or dragged/moved into the container with the $OnAdd code.

So if you add a container of notes into another containers, the latter’s OnAdd will only act on the new container and not on its contents. so, you need to rethink your approach. Perhaps get the OnAdd to set a user boolean $NeedsRenaming to true:

$NeedsRenaming = true;

Now an agent can search for notes inside containers where $NeedsRenaming is set and then run an action:

$Text=$Name;
$Name=$Name.words(11);
$IsRenamed=true;  // uses boolean user attribute

…which takes a long title and copies it to the note’s text before truncating the title to use only the first 11 words of the original title. It sets a boolean to show the note is renamed. A different query can then find containers where $NeedsRenaming but all notes are renamed and unset the the container’s boolean.

The agent doing the renaming uses this action:

$Text=$Name;
$Name=$Name.words(11);
$IsRenamed=true;  // uses boolean user attribute
if($Container(original).contains("REN_ART")){
   $Prototype="pArticle";
};
if($Container(original).contains("REN_DOC")){
   $Prototype="pDocument";
};
if($Container(original).contains("REN_ART")){
   $Prototype="pInterview';
};

Note that as we’re using an agent, you are acting on an alias whose $Container is the agent so we need to test $Container(original).contains... and not $Container.contains...

Does that help?

1 Like

Got it. That’s very helpful. Thanks. Makes sense, too.

It does, and I think I’m following the logic. One quick question… Where would I be creating the $NeedsRenaming attribute. It seems like I’d be creating it just for the OnAdd function, and so it doesn’t feel like it would be necessary to include it as part of the prototypes.

I’ll set up a discrete file and test this to see if it works.

Many thanks for your help!

User attributes are a document-scope feature, just like system attributes. I think you are confusing creating an attribute with setting the inherited or per-note value of that attribute.

I don’t quite follow. Consider

The code I posted for setting agents would run on the child notes of the added containers (i.e. ‘aa’, ‘22’, etc.) not the added containers (i.e. Collection 1, Collection2).

Why not post your file (or a demo out-down of it) so we’ve a frame of reference from which to work. i’ll take a look at it tomorrow (as it now late here in UK). :slight_smile:

1 Like

Thanks so much for all of this, @mwra. Really appreciate it. I started off putting this together, and then realized you helped me set up a Prototype attribute that would read the p[Value] (e.g., pArticle; pDocuments). And so, that attribute and the way that I’ve configured my Tinderbox files essentially accomplishes what we were seeking to do through the $NeedsRenaming code and configuration you suggested.

But it was still incredibly helpful to build on my understanding of how these things work, and I was thinking about experimenting with your agent approach for applying this portion of code…

$Text=$Name;
$Name=$Name.words(11);

…for notes that have a pArticle value (since that’s where the function os mostly needed). Given my Prototype attribute / p[Value] set up, I was thinking that I could rewrite the code w/o the boolean so that reads something like:

if($Prototype="pArticle"){$Text=$Name;
$Name=$Name.words(11);}

I haven’t don’t much with if(condition){action} so I’m still trying to figure it out! Thanks again…

I’ll confess, I don’t really understand the last but it sounds like you’ve got the desired outcome so that’s good result. :slight_smile:

1 Like

Yes, that’s true! I’ll explain, just to clarify – and because I’d like to understand how to use if(condition){action} properly…

Basically, I’d like to shorten titles for imported notes with pArticles prototypes. So I thought this code might accomplish that within an agent:

if($Prototype="pArticle"){$Text=$Name;
$Name=$Name.words(11);}

Recall, queries use == for an equality check.

Not really as in an agent, the query and the action are separated. So use an agent query:

$Prototype=="pArticle"

and action:

$Text=$Name;
if($WordCount>11){
  // no point in processing any $Name already under 12 words)
  $Name=$Name.words(11);
}

But you might want to add some other check (a boolean attribute) so you don’t keep re-running the action.

Right, right. Thank you! I keep missing that.

Got it. That really does make sense. Though I’m a bit bummed that I’m not able to use my first if ! Thank you…

I see. I thought I might skirt the re-running problem if I inserted the code into an edict.

Read up on the difference between a query and an inline if() test. Both use a query, it’s the context that differs. But, until you take a while to get more comfortable with the difference between those two context you’ll continue to be confused. IOW, if you concentrate on that you’ll make progress faster as it will be less a case of "which box does this code go in’.

I think you are perhaps misunderstanding what an edict does. An edict is a rule that runs less often but, the important point is it still runs. That isn’t what I was suggesting. Ideally, the vent ‘fixing’ the name would be saved as a boolean and the state of the latter be checked. I’ll admit that if that test has to be run (inherited) via a prototype then an edict is the place to do it.

I don’t want to write any more code at this point as it will be easier to do when you upload your test document or we’ll be writing in endless circles. Best is to talk about a document that is a common point of reference. The document doesn’t need to have actual data (I’m aware some of your projects have a degree of sensitivity) but just use some made-up data instead that shows the same characteristics with which your document’s process and code needs to interact.