Tinderbox v9 Icon

eachLink(loopVar[,scope]){actions}


Operator Type: 

Operator Scope of Action: 

Operator Purpose: 

Operator First Added: 

Operator Last Altered: 

Operator Has Optional Arguments: 

Operator Uses Loop Variable Argument: 


eachLink(loopVar){action(s)}

The eachLink() operator examines each link for the current note, either inbound or outbound; prototype links are excluded. The local, user-named, variable loopVar argument is bound to a dictionary-type object of per-link properties, and is used in the {} enclosed action code.The Dictionary includes:

The above features are described for the Browse Links or the Links Inspector.

Count, first and list tests

Although eachLinks is functionally like a list iterator (i.e. List.each()) it works off a dynamically generated List but the loopVar is bound to each list item's Dictionary. This means the list object properties of List.count, List.first and List.last are not available.

The count of the links iterated for a given note by eachLink() is $OutboundLinkCount plus $InboundLinkCount:

var:number vLkCt = $OutboundLinkCount plus $InboundLinkCount;

The loopVar supports two special dot-operators:

In effect this mimics List.first and List.last tests as used in each() but here for eachlink(). This the following example the first if() uses the long form test for a boolean true, the second the short form—both give the same result:

	eachLink(aLink){
		if(aLink.isFirst==true){
			//this is the first link in the listing;
		};
		if(aLink.isLast){
			//this is the last link in the listing;
		};
       	};

Why might this be used? If the links are being processed so as to only export certain typed links, it may be necessary to add additional text/styling before the first and after the last link.

Operator is READ-ONLY

Be aware that eachLink() is read-only: any changes to these exposed per-link key values are not (yet) recorded as changes to the link, i.e. the link's settings cannot be changed using eachLink().

More examples

Does this note have a link of type "agree"?

	function fIsAgreeable(){
		eachLink(aLink) {
			if(aLink["type"]=="agree"){
				return true;
			};
        	};
		return false;
 	};

Or, to count the number of links from this note to tasks:

	function fLinkedTasks(){
		var:number vCount=0;
		eachLink(aLink){
			if($Prototype(aLink["destination"])=="Task"){
				vCount += 1;
			};
		};
		return count;
	};

The examples use line breaks for clarity, and the last example may equally well be stored and used in the form:

function fLinkedTasks(){var:number vCount=0;eachLink(aLink){if($Prototype(aLink["destination"])=="Task"){vCount+=1;};};return count;}; 

The latter might make sense if trying to use a function within something like a rule, but if the code is defined in a Library note within Hints, then there is little gain in a one-line approach as it can be hard to read.

eachLink(loopVar,scope){action(s)}

From v9.5.0, an optional second argument for eachLink() allows designating the note whose links are to be examined, using a designator as the scope argument. Previously, eachLink() was explicitly bound to the current note.

For example,:

	eachLink(aLink, parent){
		… // action code here
	};

performs an action on each of the links to and from the parent of the current note (i.e. this note). To iterate the links of list of notes, consider the following:

	$MyList.collect(children,$ID);
	$MyList.each(anID){
	   eachLink(aLink,anID){
	      // do stuff on the links of the note defined by current anID's $ID
	   }
	};

The latter might as easily be done with a function, that takes $ID as an input and wraps the eachLink() loop using the passed-in ID as the eachLink() second argument.

Where the designator argument would be this, it may be omitted as the original usage eachLink(aLink){…} automatically assume the context of the action performed on each link to and from this note.

Editing link properties

In eachLink() loops, the following properties of the link are editable:

For example, to change any of the current note's 'untitled' links to link type 'reference':

	eachLink(aLink){
		if(aLink["type"] == "*untitled"){
			aLink["type"]  = "reference";
		}
	};

If the link type being set does not already exist, it is created and applied. But, what is the note to be checked is not the current one? Consider working via an agent, where the current note is an alias. In that case, it is necessary to use the optional scope argument and adittionally rather than specify a note name or path to use the original designator. The same task as above now becomes:

	eachLink(aLink,original){
		if(aLink["type"] == "*untitled"){
			aLink["type"]  = "reference";
		}
	};

the only change being the extra use of the scope argument to define the correct context for evaluating the links.