[Tex/LaTex] Associate dynamic text to a label

cross-referencinglinksmacros

I'm trying to associate some text (dynamically generated with counters) to a label, so that I can refer to that label and print the text associated(without re-generating it, that would cause problems with counters).

Example of usage:

\textLabel{key}{\dynamicText}

Somewhere, after, in the document i want to have a new macro that links to key and displays the text generated by \dynamictext.

This macro does not quite work:

\makeatletter
\newcommand{\textLabel}[2]{%
    \protected@edef\var{\expandafter\noexpand#2}%
    \label{#1}\var%
    \global\expandafter\def\csname#1\endcsname{\hyperref[#1]{\var}}%
}
\makeatother

The macro \var seems to work just fine.
The problem is that the macro identified with \#1 is nor visible in the document, and produces an error (control sequence not found).

Where am I goingwrong?


Context:
I have a long list of items that need an unique ID in some strange format.
I'm automatically generating the ID for the items in the list, with a call to a macro that increases some counters and returns the IDs in function of the values of the counters.

Now, I want to write the IDs generated and refer to the items, without the need of recall the macro used to build them. (It would mean to call the \getID in the same order and number of times, and I don't want it)


Here a minimal (not) working example:

\documentclass[11pt]{report}       

\makeatletter
\newcommand{\textLabel}[2]{%
    \protected@edef\var{\expandafter\noexpand#2}%
    \label{#1}\var%
    \global\expandafter\def\csname #1\endcsname{\hyperref[#1]{\var}}
}
\makeatother

\newcounter{req}
\newcommand{\getid}[1]{%
    \stepcounter{req}%
    #1.\arabic{req}%
} 

\begin{document}
    \begin{itemize}
        \item \textLabel{itemkeyone}{\getid{ITEM}}
        \item \textLabel{itemkeytwo}{\getid{ITEM}}
    \end{itemize}

    \itemkeyone %I want: ITEM.1, instead produces command not found
\end{document}  

Here a minimal working example, but with the wrong behaviour:

\documentclass[11pt]{report}       

\usepackage{hyperref}

\newcommand{\textLabel}[2]{%
    \label{#1}#2%
    \global\expandafter\def\csname#1\endcsname{\hyperref[#1]{#2}}
}


\newcounter{req}
\newcommand{\getid}[1]{%
    \stepcounter{req}%
    #1.\arabic{req}%
} 

\begin{document}
    \begin{itemize}
        \item \textLabel{itemkeyone}{\getid{ITEM}}
        \item \textLabel{itemkeytwo}{\getid{ITEM}}
    \end{itemize}

    \itemkeyone %I want: ITEM.1, instead produces ITEM.3
\end{document}  

Thank you very much

Best Answer

Here is a completely different approach using pgfkeys. With all of the comments the code is longer than Manuel's so pehaps I can't claim simplicity, but I just like using pgfkeys for things like this.

To show that it works here's what my code produces: enter image description here ...and here is the code:

\documentclass{article}
\usepackage{etoolbox}

\usepackage{pgfkeys}
\pgfkeys{/MyLabels/.is family, /MyLabels,
  % set labels using \pgfkeyssetvalue => can test with \pgfkeysifdefined
  % This allows arbitrary new keys to be defined on the fly
  .unknown/.code={\pgfkeyssetvalue{/MyLabels/\pgfkeyscurrentname}{#1}},
}

\newcounter{getID}% a dummy counter to imitate \getID

\newcommand\SetLabel[1]{% set label to current value of getID
  \stepcounter{getID}% might want \refstepcounter in real life
  Settting: #1 = ID\arabic{getID} %
  \pgfkeys{/MyLabels,#1/.expanded=ID\arabic{getID}}% force expansion
  (stored value: \pgfkeys{/MyLabels/#1}).
}
\newcommand\UseLabel[1]{% print label if it bas been defined
  Getting: #1 =
   \pgfkeysifdefined{/MyLabels/#1}%
      {\pgfkeysvalueof{/MyLabels/#1}}% print if defined
      {???}% question marks if not defined
  .%
}

\begin{document}

\SetLabel{first}

\SetLabel{second}

\UseLabel{first}

\UseLabel{second}

\UseLabel{first}

\end{document}

Edit: Solution II

I realised that this is all overkill: you should just be using LaTeX's \label and \ref commands. When you create a label what happens is that the current value of \@currentlabel is written to the aux file and this is then accessible on the next compile using \ref. So if you set \@currentlabel to the output of \getID then you are done. You can't, however, set \@currentlabel equal to \getID{item} because the \getID command contains some unexpandable stuff. Instead you should make \getID set a dummy variable or, better still, set \@currentlabel.

Here is a second solution based on your MWE:

\documentclass[11pt]{report}

\newcommand\textLabel[2]{\getid{#2}\label{#1}}

\makeatletter
\newcounter{req}
\newcommand{\getid}[1]{%
    \stepcounter{req}%
    \def\@currentlabel{#1.\arabic{req}}%
}
\makeatother

\begin{document}
    \begin{itemize}
        \item \textLabel{itemkeyone}{ITEM}
        \item \textLabel{itemkeytwo}{ITEM}
    \end{itemize}

    \ref{itemkeyone} %I want: ITEM.1

    \ref{itemkeytwo} %I want: ITEM.1
\end{document}

As this is using \label and \ref behind the scenes the labels will persist from one compile to the next but you will need to compile the document twice before it takes effect.

Here's the output:

enter image description here

Related Question