Update field value of tagged tiddlers

hi

i am trying to use a macro to take all tiddlers tagged with other tiddlers,and carry over a specific field value from said tiddlers to the ones they are tagged with

so for ex tiddler A tagged with tiddler B , tidder A has in the field “endd” a value of “x” , i want this value to be copied over to tiddler B “startd” field
so after pressing the button , tiddler B would have “X” in the “startd” field value same as TiddlerA “endd” field value

the below macro almost achieves this , so it will take all tiddlers in the wiki , find the tiddlers they are tagged with ,and update the “startd” field value with X, the problem is that the field it is drawing from is the one in the tiddler that i am running the macro in , which is an independent tiddler .

so basically i want to run the macro from Tiddler C, to update Tiddler B from Tiddler A’s field value , whats happening is that its updating tiddler B from tiddler C’s field value ,the one i am running the macro form

, how can i reference the “endd” field for tiddlers like A that are tagged , and are external from tiddler C that i am running the macro from

i hope this makes sense

\define push-enddate()
<$list filter="[tags[]]" variable="thisTag">
<$action-setfield $tiddler=<<thisTag>> $field=$field$ $value={{{ [{!!endd}] }}}/>
</$list>
\end

<$button actions=<<push-enddate startd>>>
push
</$button>

Try this:

\define push-enddate(field1, field2)
<$list filter="[tags[]!is[system]]" variable="thisTag">
<$list filter="[<thisTag>tagging[]has[$field1$]]" variable="source">
<$action-setfield $tiddler=<<thisTag>> $field=$field2$ $value={{{ [<source>get[$field1$]] }}} />
</$list>
</$list>
\end

<$button actions=<<push-enddate endd startd>>>
push
</$button>

Alternately, if B!!startd will always match A!!endd, then you might not actually need the startd field on B: when you need that information, you can use a filter to retrieve it from A!!endd instead. For example:

<$text text={{{ [{!!startd}] ~[<currentTiddler>tagging[]get[endd]] }}} />

This will display the startd field if Tiddler B has one; if not, it will display the value of Tiddler A’s endd field.

2 Likes

Thank you very much,

this works perfect, and i do need the startd field populated despite being identical to the end date field in the other tiddler , as i am planning to lay them out on a time line ( or at least attempt to )

however i ran into another problem i was not anticipating ,multiple tiddlers could be tagged with the same tiddler , so multiple tiddlers could be tagged with tiddler B,now the button sitll works, but it seems that TW takes the most recent tiddler created i guess , or at least it seems to be the case , however in ,my case i want to actually use the largest value in the endd field , so if tiddler A has “1” in the endd field , and tiddler Z has “2” , and both are tagged with tiddler B, i want tiddler B to be populated with 2 , and not 1 ,

i tried in the second list filter a sort , adding sortsub:integer[$field1$] , didn’t do any difference , would i be using the correct approach here?

You were very close! In this case, you don’t need sortsub because you’re not sorting by the result of another (sub)filter; nsort should do (or sortan, if there’s any possibility of non-numeric characters in that field.) Since you want the highest value to appear first, use !nsort to reverse the standard sort order. Then we can use first[] to ensure that only the first (=highest) value is passed to the action widget.

This last step is important because otherwise, the action widget will be executed more than once - once for each result of the second filter - and overwrite the previous value of the field at each step. The last execution will be the one that sets the field to the lowest value - so we want to stop after the first $action-setfield.

\define push-enddate(field1, field2)
<$list filter="[tags[]!is[system]]" variable="thisTag">
<$list filter="[<thisTag>tagging[]has[$field1$]] +[!nsort[$field1$]first[]]" variable="source">
<$action-setfield $tiddler=<<thisTag>> $field=$field2$ $value={{{ [<source>get[$field1$]] }}} />
</$list>
</$list>
\end

You can try something like…

\define push-date(tag)
<$button tooltip="push the largest endd value to $tag$ startd">
push
<$list variable="LargestEndD" filter="[all[tiddlers]tag[$tag$]!sort[endd]first[]get[endd]]">
<$action-setfield $tiddler="$tag$" startd=<<LargestEndD>> />
</$list>
</$button>
\end

In tiddler C, call the macro with <<push-date "tiddler B">> — where “tiddler B” is whatever tag you want updated with the largest value of endd. You should get something like this…

Depending on the values being used, you may need to try one of the other sort operators in:

filter="[all[tiddlers]tag[$tag$]!sort[endd]first[]get[endd]]"

both solution work . again thankyou very much.

one last favor if possible, what if i want the tagged tiddler not only to have its start date set as the end date of the tiddler tagged with it , but also to have its end date pushed with the difference in value between the old start date and the new start date, so for example if the end date was 2 , and the start date was 1 and changed to 2,then the end date would change to 3

thanks again for all your help

Try this in place of the code I gave you earlier:

\define push-date()
<$list filter="[tags[]!is[system]]" variable="thisTag">
<$list filter="[<thisTag>tagging[]has[endd]] +[!nsort[endd]first[]]" variable="source">
<$let 
	oldStart={{{ [<thisTag>get[startd]] }}}
	oldEnd={{{ [<thisTag>get[endd]] }}}
	newStart={{{ [<source>get[endd]] }}}
	newEnd={{{ [<oldEnd>] =[<newStart>subtract<oldStart>] +[sum[]] }}}
>
<$action-setfield $tiddler=<<thisTag>> $field=endd $value=<<newEnd>> />
<$action-setfield $tiddler=<<thisTag>> $field=startd $value=<<newStart>> />
</$let>
</$list>
</$list>
\end

<$button actions=<<push-date>>>
push
</$button>

Some notes:

  • I replaced the macro variables in the macro definition with the values you’re using, to make it easy to parse.
  • I also defined new and old start/end dates with the let widget, again for clarity. You’re basically doing algebra at this point, and it’s easier (from a human point of view) to work with variables than raw filter runs.
  • We’re setting the new endd before the new startd so the old startd doesn’t get overwritten before it can be used.
  • We need that equals sign before the second filter run in the newEnd definition to ensure that it’s not ignored if its value happens to match <<oldEnd>>. Otherwise, a duplicate value would be excluded by the automatic de-duplication process.

thank you

is it possible to make this macro recursive and to iterate through every single instance where Source is not equal to old start date

i tired defining a condition (outcome) in the let widget then call the macro actions from an additional filter if the condition is met

it doesnt work :frowning:

i know i need something to break the loop, because i tried calling the macro from withing itself and tw crashed

\define push-date()
<$list filter="[tags[]!is[system]]" variable="thisTag">
<$list filter="[<thisTag>tagging[]has[endd]] +[!nsort[endd]first[]]" variable="source">
<$let 
	oldStart={{{ [<thisTag>get[startd]] }}}
	oldEnd={{{ [<thisTag>get[endd]] }}}
	newStart={{{ [<source>get[endd]] }}}
	newEnd={{{ [<oldEnd>] =[<newStart>subtract<oldStart>] +[sum[]] }}}
   outcome={{{ [<newStart>compare:number:eq<oldend>then[yes]else[no]] }}}
>


<$action-setfield $tiddler=<<thisTag>> $field=endd $value=<<newEnd>> />
<$action-setfield $tiddler=<<thisTag>> $field=startd $value=<<newStart>> />

<$list filter="[<outcome>match[yes]]" emptyMessage="not equal"><<push-date>></$list>

</$let>
</$list>
</$list>



\end

<$button actions=<<push-date>>>
push
</$button>

It’d be easier to troubleshoot on my end if you could provide a small sample data set (either via tiddlyhost.com or as a json attachment; no private data needed, obviously, just the relevant fields) but I’m guessing the issue is that you have multiple nested layers of tags that all need to have dates updated? Without getting into recursion, one quick solution would be to tweak the button so that it will tell you when updates are still needed, e.g.:

\define push-date()
<$list filter="[tags[]!is[system]]" variable="thisTag">
<$list filter="[<thisTag>tagging[]has[endd]] +[!nsort[endd]first[]]" variable="source">
<$let 
	oldStart={{{ [<thisTag>get[startd]] }}}
	oldEnd={{{ [<thisTag>get[endd]] }}}
	newStart={{{ [<source>get[endd]] }}}
	newEnd={{{ [<oldEnd>] =[<newStart>subtract<oldStart>] +[sum[]] }}}
	outcome={{{ [<newStart>compare:number:gt<oldStart>then<thisTag>] }}}
>
<<outcome>>
<$action-setfield $tiddler=<<thisTag>> $field=endd $value=<<newEnd>> />
<$action-setfield $tiddler=<<thisTag>> $field=startd $value=<<newStart>> />
</$let>
</$list>
</$list>
\end

<$button>Synchronize:
<<push-date>>
</$button>
1 Like

Thank again :slight_smile:

https://mighty-soap-71.tiddlyhost.com/

this is really an attempt to push an entire schedule comprised of tasks linked by tags , so pushing 1 pushes all the ones ahead , something i have been dreaming of having

tiddly map is installed in the side bar for better visualizing