How to create field relationships, where modifying a field in one tiddler modifies a field in another

I’m relatively new to tiddlywiki, so please have some patience with me.

I’m trying to figure out a way to have a relationship between two fields in two different tiddlers where if I change a value in one, the corresponding value changes in another tiddler.

An example for clarity:
I have two tiddlers: Jane Doe and John Doe. In both, there are fields labeled “parents” and “children.” If I’m working on John’s tiddler and Jane is John’s mother, I would put [[Jane Doe]] in the “parents” field for John. What I want to have happen is that the “children” field for Jane then has [[John Doe]] immediately added, without me having to add it myself. Further, if Jane already has children [[Jeff Doe]] and [[Josh Doe]] in the “children” field, I’d like to just have [[John Doe]] added to the already existing list.

Is there a way to do this? I figured out how, through filters and transclusions, to get a list of children for every tiddler that lists Jane Doe as a parent, but I’d like for it to be mutual and for both fields to be able to modify the other without losing the data that’s already there.

I’m also sure that this can probably be accomplished via adding a button or the like, but I’d love for it to just be automatic when a tiddler is saved, if at all possible.

Hello @Ryan_Quinn!

Generally, the best approach here is not to duplicate any data. In other words, rather than having the same relationship-info stored in two places, make the tiddler for one participant in the relationship serve as the real location where the info lives, and make the other location simply display related data…

In the case of parent-child data, I recommend putting the data in the child tiddler. This is because the child — as soon as it exists as an entity — has some relation to a parent. Meanwhile, the parent can exist for a long time, and evolve over time with respect to how many children exist in relation to that parent.

So if the “parent” field in the tiddler for a child is where the data lives, then the tiddler for the parent will need to have some place to show that person’s children. A simple way of showing that info might look like <$list filter="[parent<currentTiddler>]"/>

3 Likes

@Springer’s advice to avoid duplicating data is 100% correct. It generally avoids complications caused by having multiple “sources of truth” that need to be kept in sync.

Nonetheless, it is entirely possible to do what you asked… and is also relatively easy to implement…

We can start by noting that the TWCore’s tiddler editor “done” button (the checkmark) is defined in $:/core/ui/Buttons/save and examining that code shows a procedure named save-tiddler-button(), which contains this line:

<<save-tiddler-actions>>

save-tiddler-actions() is defined in $:/core/ui/EditTemplate, and performs some “cleanup” actions and then sends a tm-save-tiddler message to actually update the stored tiddler.

While we COULD modify the save-tiddler-actions() definition, the easiest way to add your own “side effect” actions would be to modify $:/core/ui/Buttons/save by adding just one line in the save-tiddler-button() procedure, immediately before <<save-tiddler-actions>>, like this:

<<save-tiddler-actions-custom>>
<<save-tiddler-actions>>

Then, in a separate tiddler (e.g., “MySaveTiddlerActions”) tagged with $:/tags/Global, you would define the save-tiddler-actions-custom() procedure that performs your desired changes to the related fields in other tiddlers. For example, to update the “children” list field in the respective “parent” tiddler(s):

\procedure save-tiddler-actions-custom()
<$list filter="[enlist{!!parents}]" variable=thisparent>
   <$action-listops $tiddler=<<thisparent>> $field="children" $subfilter="[{!!draft.title}]"/>
</$list>
\end

Note the use of !!draft.title in the subfilter. This is because, when editing the “John Smith” tiddler, the current !!title field value will be “Draft of ‘John Smith’” while the !!draft.title field specifies the title that will be given to the tiddler when it is saved.

Also note that the above actions only ADDS a child to the parent tiddler’s children list field. If you were to edit the “John Smith” tiddler and change the parents list field value from [[Jane Smith]] to [[Betsy Ross]], while <<save-tiddler-actions-custom>> will correctly add [[John Smith]] to the children list field in the “Betsy Ross” tiddler, it will not REMOVE the existing [[John Smith]] item from the children list field in the “Jane Smith” tiddler.

To perform the removal actions, you would first need to find all tiddlers for which the children field already contains the !!draft.title value, and remove that value. Then, you can add the !!draft.title to the new parent tiddlers. Something like this:

\procedure save-tiddler-actions-custom()
<$list filter="[contains:children{!!draft.title}]" variable=thisparent>
   <$action-listops $tiddler=<<thisparent>> $field="children" $subfilter="-[{!!draft.title}]"/>
</$list>
<$list filter="[enlist{!!parents}]" variable=thisparent>
   <$action-listops $tiddler=<<thisparent>> $field="children" $subfilter="[{!!draft.title}]"/>
</$list>
\end

Let me know how it goes…

enjoy,
-e

3 Likes

You have an answer from Eric that does tell you how to do what you want to do. And you may still want to do it!

To illustrate the logic of one reality, one storage-place I give you an analogy: I have a database of bibliographic records. It’s mostly books, but sometimes it’s necessary to cite, directly, a chapter from a book. So I make a separate record.

Now, can you imagine the mess that could develop if I wanted each book to have a field listing the book’s chapters, while also having tiddlers for those chapters, where the chapter’s “parent” (enclosing book title) also lives?

Instead, a tiddler for a chapter stores info about what the “parent” record is (in this case, a book). AND, the tiddler for a book includes a view template that displays connections to any tiddlers in my wiki that are the “children” of that book. The relationship lives in only one place, but I can see it from both places.

https://biblio-springer.tiddlyhost.com/#emerson1996ralph

2 Likes

I agree with everyone here that doing one or the other will make your life much easier down the road. I’ll offer a reason to store things at the parent level though instead of the child level. Essentially, SORTING.

If you just store the name of the parent for each child, there’s not a real way to maintain any manual sorting (if that may be desired). If you however on the parent tiddler use the list field (or any other but list offers some conveniences) then you have a sort order that can be maintained. Listing the children from the parent is just [list<currentTiddler>] and finding the parent from a child is just [<currentTiddler>listed[]].

In fact you’ll notice that core tag behavior is that when you do drag-and-drop sorting within a tag pill, that’s stored in the list field of the tag tiddler, just as I’m describing, so it’s a well supported method.

3 Likes

It’s rare for me to desire a genuinely manual (arbitrary) sort; bibliographic subentries —and children — both tend to have a natural order that tracks something (page, birthyear) that’s already easy to reference…

But certainly if you do want such a thing (to order children by current-preference-ranking-according-to-this-parent :stuck_out_tongue: or some such), then the list field for the parent tiddler is the best place to do it (and once you have that list field, it ought to be the “home” for such data).

Alright, I think I understand the benefit of using only a “parent” field and then generating the “children” within the tiddler for the parent. But what if a relationship is mutual, like (in keeping with the example of a person) a “spouse” field or a “friend” field? What would be best practices there?

And thank you for providing a solution that solves the problem exactly as I wrote it, even if storing the data that way is not best practice.

You can create a list field that contains multiple titles to link to other relationships or just link to them in the body. Try ctrl-L in the text editor to see how easy this is.

  • Of course installing RELINK plugin is all but essential, if not essential to maintain referential integrity if a rename happens.

Welcome, @Ryan_Quinn to the talk forums!

I have a substantially different approach.

This is a demonstration of using small external tiddlers to maintain relationships between content tiddlers. You can see all the People in this wiki, who are extracted from the Adams family tree on Wikipedia: John Adams (the second president of the U.S.A), his wife Abigail Adams, and a few generations of their descendants.

If you view a person, say John Quincy Adams, you will see a reasonably robust template describing his vital stats and relationships:

But if you edit this tiddler, you will see that none of the relationship information—parents, children, siblings—is actually included in this tiddler. The only custom fields are name, born, died, caption, and where needed, maiden-name.

Instead of putting the relationship information inline, we have a number of separate ParentChild tiddlers that have only a numbered title, the tag ParentChild, and parent and child fields, which each have the title of another Person:

<!-- John Quincey Adams is `Person/5` -->
<!-- These are his parents -->

title: pc/3
tags: ParentChild
parent: Person/2
child: Person/5

title: pc/4
tags: ParentChild
parent: Person/1
child: Person/5

<!-- and these are his children -->

title: pc/10
tags: ParentChild
parent: Person/5
child: Person/9

title: pc/12
tags: ParentChild
parent: Person/5
child: Person/10

title: pc/14
tags: ParentChild
parent: Person/5
child: Person/11

These are used by the ViewTemplates named $:/_/my/viewtemplates/person, to display those parents, children and siblings. For example, we list the Children like this:

  <% if [tag[ParentChild]parent<currentTiddler>] %>

    !!! ''Children''
    <<list-links filter:"[tag[ParentChild]parent<currentTiddler>get[child]sort[born]]">>
  <% endif %>

Parents is similar. Siblings is significantly more complex.

We could extend this to First Cousins, or add a recursive version of Descendants. If we added gender fields, we could also do Aunt, Uncle, Niece and Nephew. We could track half-siblings and step-siblings, and many other relationships, all within our templates, without adding any data. We could add other relationship tiddlers, for instance, Spouse.

You can also look at the Families tiddler, for another view of this data.

There is work to do to set this up. You need to create all those relationship tiddlers. To do so, I often add helpful input screens. Here, I have Add Family, which lets me pick the parents and children, click a button and have the relationship tiddlers added for each parent-child combination from my inputs.

This is not a panacea. The filters for siblings are non-trivial, and cousins would just be harder. But it’s powerful and I find it very useful.

2 Likes

Update:

In my previously posted solution, I suggested that you

While this works, it only handles saving the tiddler by clicking on the “done” (checkmark) button. However, you can also trigger the <<save-tiddler-actions>> without clicking the “done” button by using the ctrl-enter keyboard shortcut while the focus is in a tiddler input field. This trigger is defined by a $keyboard widget that is directly in the $:/core/ui/EditTemplate tiddler.

So, in order to cover BOTH use-cases (clicking the “done” button OR using ctrl-enter), the best place to make your change is in $:/core/ui/EditTemplate, by adding the call to <<save-tiddler-actions-custom>> at the beginning of the save-tiddler-actions() definition. This ensures that regardless of how <<save-tiddler-actions>> is invoked, your extra “side effect” handling is performed.

The rest of my instructions (i.e., defining the save-tiddler-actions-custom procedure) remain the same.

enjoy,
-e

2 Likes

Yes! This is exactly what I would find most logical if I had a wiki really focused on people and their relationships. (I know I suggested, above, making a parent field within the child tiddler. Which way to go depends on your situation and the needs of the project.)

In particular, with marriage or other reciprocal relations, a robust solution would want to allow that a person can participate in more than one over the course of time. If your approach is field-based, and there’s just one “spouse” field, then you would need to figure out whether to replace contents of a spouse field (losing real relational info) or whether to make a “spouse #2” field (also a mess for various relations), etc. But If a marriage is itself a tiddler as suggested by @Scott_Sauyet, then the information lives in one place, and can have start and end dates, plus other fields that might be genuinely specific to that marriage.

One risk that comes with putting relationship info in distinct tiddlers is that you need to anticipate some future contingencies. In particular, name changes…

Especially if you have a large project of this kind, you’d want to be careful to set up tiddler titles in a way that preserves uniqueness and flexibility in connection with ordinary names. Indeed, human beings can change their names, and it’s important that changing a person’s name can happen without losing the continuity of an individual’s info (and relationships) over time.

If names are tiddler titles, which then function as a key field for relationship connections… some of the risks of this easy approach are addressed by relink-type solutions now built into TiddlyWiki — so that if you change the name of a tiddler, you’re prompted about whether to change apparently related instances of that name in links and fields. Still, such solutions might leave some unexpected gaps that require caution.

We do have some genealogy wiki experts in the house… @clsturgeon comes to mind…?

2 Likes

I replied to the OP on a duplicate post on Reddit. My response was similar to those here. ie avoid duplicate linking. In the Memory Keeper I have dedicated father and mother title fields for biological relationships. That’s it. I use a spouse list field for spouses. One more… an adopted list field. From there users can create their own relationships. These are set up like the spouse list field.

I guess I avoided a relationship tiddler type. Relationships, those non-blood, are dynamic… they come, they go, they come back. Marriage, divorce, etc are events, so users use an event to capture these.

And, yes I use the name of the person for the tiddler title. Without Relink plugin this would be a non-starter. I recommend the user use the birth name of an individual/title. I use an Aka field for alternate names, different spellings, nicknames etc. Name changes, in my mind, are events.

With blood relationship only being defined via a father and mother field made it ideal for writing TW filter operators like:

ancestors[]
descendants[]
uncles[]
aunts[]
siblings[]
cousins[]

2 Likes

That’s an interesting insight. My version sounds similar to yours, except that I externalize Mother/Father (without distinguishing them; for something more than a POC, I would.) Marriages I did assume to be events but perhaps almost everything should be fluid this way. Keep an id, dob, date of death (if known), and use event tiddlers tied to that id for everything else: marriage, divorce, birth of a child, name change, sex change, etc. To know someone’s marital status at a given point, just look through the related events preceding that time. And that makes me even reconsider dob/date of death fields.

As to the names, I think as wikis add functionality or data, it gets trickier and trickier to use tiddler titles. Of course we all can imagine things we’d change about TW if we could go back in time. The top of my list is using a field called title and often meant to be a title, for the tiddler’s unique id. I think life would be much easier with a unique generated id instead.

I appreciate all of the responses here, and you’ve all certainly given me a lot to think about.

I think that Scott_Sauyet’s solution is probably going to solve the most problems for me while still allowing me to maintain the best practice of not duplicating data, and I can probably use this approach for multiple types of relationships within my project. That said, I’ve realized two potential problems with this approach that I wanted to run by all of you:

  1. Naming of relationship tiddlers – If I use separate tiddlers for every relationship, naming those relationships could start to pose an issue. For instance, if I take the approach of just naming them “rel” and then adding a number, would it not make figuring out what that relationship is or finding later very difficult should I need to edit it? What would be best practice here?

  2. Number of relationship tiddlers – I can see how this approach could become very cumbersome very quickly, with some tiddlers potentially having tens of relationships. When multiplied across hundreds of individual tiddlers, you’re looking at thousands of individual relationship tiddlers. Would that cause any problems down the line?

Thoughts?

I’ve done a few data models and each time I have not implemented a dob or dod attributes for a person entity. I suspect most applications have these. To me birth and death events are events. Separating them from the event entity will make it tougher to draw a timeline. I took events to another level. Events can be part of a greater event. Eg. The death of Tecumseh is child event to the Battle of the Thames; which is a child event to the War of 1812. Tough to do with a dod field. Another dimension of an event are the other people that participated in the event, capturing the role they had in the event. I’m researching beyond names and dates. I’m researching battles in WW1, WW2, and War of 1812. I research Indigenous Treaties and various colonial and Indigenous battles. I research organizations: business, military and Indigenous Nations.

1 Like

One way I have designed to handle this is leveraging relink but also providing the tools to rename or change relationships, if it is likely to result in a loss of information such as remove or change a spouse name/link to log this to a transaction tiddler. This can mean you do not loose information. But of couse it raises the issue of when someone was a spouse start and or end, do they stop being a spouse when the other dies etc…

  • An appropriatly maintained transaction history can then be walked back to see the data accross time.

I think a relationship tiddler can work. Some data models have a family entity to fulfill that. I don’t. I see family as something that can be determined vs explicitly defining it.

Your concerns are valid. The volume may not be a direct issue except when you want to write a relationship calculator, where you provide two individuals to a method and it returns the relationship. The calculator has to recursively go through the person and relationship / family tiddlers. All doable. If done correctly, I suspect it would be no more taxable on the system than my model.

However, it will be another entity to maintain and that is the concern with your first point. Not sure I have good answer for this. In my solution I don’t expect the user to use the TW edit fields. I provide my own to fill those TW fields. This helps with data integrity. With that, one could auto generate relationship tiddlers without the user knowing they exist. Provide appropriate controls to add, edit, and delete relationships.

Not tiddlywiki.

Please ignore this reply

This is an example of a friendship

query and click - Structured speech similar to writing programming code (ssspc)

Not tiddlywiki.

Please ignore this reply

This is an example of a event

https://tomzheng.codeberg.page/talking-structured-like-program-code/example/event.html