You are viewing limited content. For full access, please sign in.

Question

Question

Displaying Single Line field value as a clickable URL (text as a hyperlink)

asked on February 6, 2020 Show version history

Me and a coworker have been banging our heads against this for a couple of days, should have asked sooner!

 

We have a Form that acts as a task tracker and is initiated by Workflow.  Workflow pre-populates a table with the list of tasks the user is to complete.  SOME of these tasks have a URL associated with them.  Rather than having a column of ugly URL's, what we've been trying to accomplish is attaching the URL to the name of the task, such that the task name becomes a hyperlink.

 

Thus far, we have had some success conditionally creating the HTML in Workflow, such that the value of the task name is driven by this token: 

<a href="%(Task URL#[%(ForEachTask_Iteration)]#)" target="_blank" class="taskURL">%(ForEachTask_Current Value)</a>

 

In this example, "ForEachTask_Current Value" is the name of the token, and "Task URL" is of course the URL.  We use the following javascript to utilize the HTML code rather than just displaying it:

  $('.taskTable .taskName').not(':first-child').each(function(index,element){
    
    var display = $(this).find('input').val();
    //$(this).find('input').hide();
    
      //debugger;
      $(element).before($(display));
    
    alert(display);
  });

This causes some odd formatting (eg, table values that are higher than they should be, and having to make sure the column takes up the full table width because otherwise the html code shows to the right of the hyperlink).  It does more or less work, but we've discovered that any tasks with special characters (such as an apostrophe) break the loop, and the code fails to execute for any subsequent values.

 

We did try using "replaceWith" instead of ".before" but for some reason that completely dropped any value that didn't have an associated hyperlink.

 

I'm thinking there MUST be an easier way to accomplish this.  Can anyone help?

Using Forms 10.4.1

 

EDIT:  Here's a screenshot of what we're trying to accomplish.  Note the slightly raised "Task Name" value for hyperlinks and the fact that the apostrophe in "Driver's Training" broke it:

1 0

Answer

SELECTED ANSWER
replied on February 7, 2020

Ok. So I got it working, FINALLY. It was all in my selector for the element. Here is a quick write up on how I did it (in case someone else needs this in the future).

 

So first thing, here is my code:

//Makes Task Name a link if there is an associated URL
  $('.taskTable .taskName').each(function(index,element){
    
    var display = $(this).find('input').val();
      
      $(element).html(display);
    
  });

So now I'll explain what it does and how. The first part is looking at each table cell with the class "taskName" in the table with the class "taskTable". The (index, element) is the position of the index (index are numbers to tell you which row you're on) and the element you're currently on (more relevant if you are going through multiple elements, but also useful for control of the element your on).

From there I set a variable (which changes with each row since it's set within the .each loop. The variable is set as: $(this) is the current element your on. Which, in this case, is the .taskName element. The .find() finds the "input" element within the current .taskName (in this case the input where the link text is). The .val() is to get the value inside the input element inside the .taskName element.

After I get the variable's value I use what Chad said (this is one way, there are technically multiple ways to do it also) and replace the entire ".taskName" element with the value of the variable "display". This wipes on the input box and places the HTML or text (depending on what was set in Workflow) in its place.

Once it cycles through you get what looks like the picture below:

That is a table populated from an initiation form and ran through Workflow. The links are linked to Weblink documents that the user can review then mark as completed on this form. Workflow takes the responses from the initiation form and sets a token to either

A:

<a href="%URLSetInWorkflow" target="_blank" class="taskURL">%NameOfAssociatedTask</a>

or

B:

%NameOfAssociatedTask

 

The Javascript is what either sets the Name to a link or just simple text.

 

I think that covers the basics of how to do this, if someone likes this idea and wants the specifics of the Workflow or the initiation form to kick this off, just let me know. I hope I help someone in the future by solving my problem. This gave me a strong lesson in JS and Laserfiche Forms. Good luck everyone!

1 0
replied on February 7, 2020

I've been hanging back and letting Tanner respond, since he's better at Javascript than I am, but so glad to have the answer!  Also, thank you Chad for your input!

One final note on this for any future users:  the end result from our javascript creates a table row that is slightly offset from the previous row.  We found that adding 4 px of padding to the input brought it down in line so that the table looks even. 

 

Identifying the element seems to be a bit tricky.  To shift the value down a bit, we identified the table directly and "navigated" down to the correct class element, like so:

#q14 > div.cf-table_parent > table > tbody > tr > td.taskName {padding-top: 4px;}

 

1 0
replied on February 7, 2020

Cool, sounds like it was just a problem iterating through the loop.

Funny thing is that I don't see a difference between your working code

//Makes Task Name a link if there is an associated URL
  $('.taskTable .taskName').each(function(index,element){
    
    var display = $(this).find('input').val();
      
      $(element).html(display);
    
  });

and your original code

$('.taskTable .taskName').not(':first-child').each(function(index,element){
  
  var display = $(this).find('input').val();
  //$(this).find('input').hide();
  
    //debugger;
    $(element).before($(display));
  
  alert(display);
});

Outside of switching to the .html method and no longer ignoring the first row.

1 0
replied on February 7, 2020

That's the "beauty" of it. I took the first child off to save some processing and because the each loop iterates well enough without it. The nail in the coffin of this problem was in the .before(). Since I was using $() it saw a ' and thought there was more to the selector when there wasn't. I switched it to .before(display) without the selector within the parenthesis and it just worked. That was my hang up and from there I changed it back to .html() since it works nearly the same as .before() (in this example).

 

So the selector in the before method was my issue the whole time basically.

0 0
replied on February 7, 2020 Show version history

Hi Chad,

 

Switching to the HTML method does a nicer job of presenting the data (with the "before" method, we had the original data sitting awkwardly to the side, which we hid off the edge of the table).  The main key was removing the selector ( $() ) from the display so it didn't try to execute on special characters like apostrophe's.  

1 0
replied on February 7, 2020

Yes, the before method does not replace anything, it inserts new content, so your likely trying to squeeze too much into one place.

1 0
replied on February 7, 2020

Funny enough we actually just changed the size of the column to block out the rest of the content and it worked fine. Since it's not inline and the 'a' element was big enough it just pushed the rest of the content out of the way and didn't display it. But .html is much more appropriate.

0 0

Replies

replied on February 6, 2020

There is a jquery method to replace all HTML in the element. This will replace the input entirely with your link. Just use $(object).html('<a href="link">Link</a>');

Example

  $('.table tbody tr').each(function(){
    
    $(this).find('.field1').html('<a href="www.google.com">Google</a>');
    
  });

 

0 0
replied on February 6, 2020

Hi Chad,

  So I'm actually the co-worker he's talking about. So your method works on some level, but not completely. The issue is we have a Name and a URL. Originally we had them in separate columns, but the user had to copy and paste the URL into the address bar which wasn't ideal.

So we created a token in Workflow that takes the Name and URL and creates a token as the HTML code to make it a link. We then inserted this into an input field in the column the Name would normally go.

Now Forms as you probably know doesn't display HTML in input fields (as it should, they are input fields). It shows them as text, so we needed to take that value (<a href yada yada) and turn it into a link, but keep it in the same spot.

So we made a .each() loop to get the values of each of the input fields and add them to the tables cell. The first couple times it didn't work because there are also going to be Names that don't have an associated URL.

This is where it got tricky, and why your code doesn't fully work the way we need it too. That code replaces the existing input field with whatever is in the (). That means the rows that have a Name that doesn't have a URL don't show up. It's probably the bigger problem than not having the link show up.

 

So to make a short story long, we are trying to get links (that are created or not in Workflow) for Name that have URL's, but not for the ones that don't.

 

This is what it looks like CURRENTLY when there are no special characters in a Task Name. The alignment is slightly off, but it's very close to the end goal. When I change my code to yours it removes the 2 Tasks that aren't links.

 

I'm hoping I'm simply missing something that you see, but Forms is giving me a run for my money on this. 

0 0
replied on February 6, 2020

I am a bit confused as to why it would remove the names that are not links. If by Name you mean only a raw string like "New Employee Orientation" instead of HTML that would still show up. Since if you replace the HTML of the element with raw text data it will display just that.

So you should simply be able to get the value of the input child object IE: let currentVal = $('.yourclass input').val() and replace the entire object's html with that value IE: $('.yourclass').html(currentVal);

0 0
replied on February 6, 2020

I wondered the same thing and haven't been able to figure it out. So one bit I can add that struck me as odd is. If you look at the code in the post I'm displaying an alert to give the value of the input for that current row. And it will give me the <a> code for the ones that have it, and it will give me the plain text for those that don't.

But as soon as the alert finishes and the page displays, the two values are blank. I don't know why, but all it tells me is that when the page first loads (and displays the alert) the values are there. Then once it finishes loading they disappear and only the links remain.

0 0
replied on February 6, 2020

If your displaying an alert between each, you should be able to see it populating each row individually. Do you see it populating the html with no value? If so, use the inspector to view the HTML contents of the element you just populated.

0 0
replied on February 6, 2020

Yeah, sorry that's what I mean. Within each loop it's displaying the value of the input field as it's inputted by Workflow. So the inputs that have <a> links display that, and the inputs that are plain text display the plain text. However, once the page finishes loading, there's no indication in the dev tools that the plain text is the value of the input. But the link is pulled out of the input and placed .before() the input.

It's a real head-scratcher and I'm trying out other ways of making this work in the mean time.

0 0
replied on February 6, 2020

It sounds like the problem needs to be simplified a bit. Try just replacing the HTML with static values, get to a point where your getting the data to stick, then go from there.

 

.html is the method that is going to swap out an existing field for something entirely different.

0 0
replied on February 6, 2020

Ok. Yeah, it's a bit complicated and yet simple enough it's only a few lines of code. Thanks for the help so far.

0 0
replied on February 7, 2020

So,

  I tried commenting out the code I was using and used your code and ran into two problems.

1. It would either only add the HTML to the last one and leave the others blank.

or

2. It would place the first row's value in every row. So for some reason the each either isn't running correctly, or something else is making it not check each row.

The code below grabs the first value of the column I'm populating from Workflow (either HTML or plain text) and then runs with it down every row. 

$('.taskTable tbody tr').each(function(){
    
    $(this).find('.taskName').html($('.linkURL input').val());
    
  });

So in a basic sense, it worked, but only for the first row then subsequent rows do now get the value they should. This might work for our situation (special characters in the plain text), but it's not hitting every row. My current code (below) does hit every row but fails if it hits a special character (in this case an ').

//Makes Task Name a link if there is an associated URL
  $('.taskTable .taskName').each(function(index,element){
    
    var display = $(this).find('input').val();
   
      $(element).before($(display));
    
    alert(display);
  });

The alert can be commented out it's for testing purposes, but it shows you the value of the current element. I was using it to tell me if the JavaScript was seeing the right value where I was selecting.

Maybe you see something, but the more I stare at this the worse I'm getting at finding a solution.

0 0
You are not allowed to follow up in this post.

Sign in to reply to this post.