Asifuzzaman Redoy Asifuzzaman Redoy - 24 days ago 8
Javascript Question

link <a> tag downloading the default html page when condition is not fulfilled

I am facing a wired problem I have a link tag to download like

<div class="col-md-4 about-right">
<ul>
<h5>Get My Cv</h5>
<li><span class="glyphicon glyphicon-user"><input type="radio"class="rad" id="radio1" name="optradio"></span>Download In PDF</li>
<li><span class="glyphicon glyphicon-user"><input type="radio" class="rad" id="radio2" name="optradio"></span>Download In Word Doc</li>
<li><span class="glyphicon glyphicon-user"><input type="radio" class="rad"id="radio3"name="optradio"></span>Download In HTML</li>
<center>
<a href="#" id="cvLink" download onclick="getCv()">
<button type="button" class="btn btn-info">Download</button></a>
</center>
</ul>
</div>


Which downloads documents using radio button checked validation.I have also 3 radio button.I change the url link based on which radio button is clicked and download the documents using javascript .But the problem is when any of the radio button is unclicked i want to show an alert and make the link to do nothing.I triedcthis by using "# , javaScript:void(0)" it shows the alert but also downloads the main html file on which i am working on .I just want the link will do nothing but show the alert only.

my code seems some thing like below

<script>
function getCv() {
if(document.getElementById('radio1').checked) {
document.getElementById('cvLink').href = "https://drive.google.com/uc?export=download&id=MZTFCWnRYbnlvclk";
}

else if(document.getElementById('radio2').checked) {
document.getElementById('cvLink').href = "https://drive.google.com/uc?export=download&id=uK6ct7MZ2N6Ni1qQUFyWXM";
}
else if(document.getElementById('radio3').checked) {
document.getElementById('cvLink').href = "https://drive.google.com/uc?export=download&id=0VDenJqUldud2M";
}

else
{

alert('Please Select Any Format To Download!!');
}
return false;
}




thanks in advance

Answer

First, before we get to the answer to your question I'd like to take a moment to point out some issues with your HTML:

<div class="col-md-4 about-right">
  <ul>
    <h5>Get My Cv</h5>
    <li><span class="glyphicon glyphicon-user">
      <input type="radio"class="rad" id="radio1" name="optradio"></span>Download In PDF
    </li>
    <li><span class="glyphicon glyphicon-user">
      <input type="radio" class="rad" id="radio2" name="optradio"></span>Download In Word Doc</li>
    <li><span class="glyphicon glyphicon-user">
    <input type="radio" class="rad"id="radio3"name="optradio"></span>Download In HTML</li>
    <center>
      <a href="#" id="cvLink" download onclick="getCv()">
        <button type="button" class="btn btn-info">Download</button>
      </a>
    </center>
  </ul>
</div>

So, the first problem is one that recurs twice, that the only valid child element of a <ul> (or an <ol>) is the <li> element. The others you have in there, the <h5> and the <center> (more on that in a moment) are invalid HTML where they're placed here.

You have the option of either removing those elements from the <ul>, as I've done, or you can simply wrap them in a parent <li> so that the DOM structure becomes valid.

Further, the <center> element has been deprecated since HTML 4.1, I think. Regardless of when it was deprecated, however, it remains deprecated and should no longer be used. If you should need to center something in your layout use CSS to style the presentation of the document, HTML should only define the structure.

Also, and I think this is the last issue with your HTML, it's invalid HTML to have an interactive element, such as a <button>, within another interactive element, such as an <a>. In my demo to reproduce your problem I simply discarded the <button> element, since it has no download attribute.

That said, the following JavaScript is my proposed solution, the HTML is also in the snippet along with the JavaScript and CSS:

// a named function to highlight the <input> elements required
// in order to enable the <a> element:
function highlightRequirements(e) {

  // caching the element that initiated the events
  // here the <a> element:
  let clicked = this,

      // retrieving the elements that are required to
      // be chosen amongst before the <a> can be used:
      required = document.querySelectorAll(

        // I store, in the <a> element the attribute:
        // data-required="input[name=optradio]"
        // here we use the HTMLElement.dataset interface
        // to retieve that selector, which is passed as
        // the argument to document.querySelectorAll:
        clicked.dataset.required
      );

  // if the event type (the event, 'e', is passed automatically
  // from the EventTarget.addEventListener() method) is the
  // 'mouseenter' event:
  if (e.type === 'mouseenter') {

    // if the <a> element has the download attribute set:
    if (clicked.download) {

      // we remove the event-listener bound to that element
      // for both 'mouseenter' and 'mouseleave' events:
      this.removeEventListener('mouseenter', highlightRequirements);
      this.removeEventListener('mouseleave', highlightRequirements);

      // and we iterate over the required elements, using
      // Array.prototype.forEach(), and an Arrow function
      // expression, to remove the 'highlight' class from
      // the parentNode of each required ('req') element:
      required.forEach(req => req.parentNode.classList.remove('highlight'));
    } else {

      // if the <a> element does not have the download property,
      // we iterate over the required elements and add the
      // 'highlight' class-name, in order to trigger the animation
      // defined in the CSS, in order to draw the users' attention:
      required.forEach(req => req.parentNode.classList.add('highlight'));
    }

  // otherwise, if the event was not the 'mouseenter' event (and so
  // must be the 'mouseleave' event):
  } else {

    // we iterate over the required elements, and remove the 'highlight'
    // class-name from their parentNodes:
    required.forEach(req => req.parentNode.classList.remove('highlight'));
  }
}

// a named function, fired by the radio inputs, to
// 'enable' or 'activate' the <a> element:
function linkActivate(e) {

  // we use document.querySelector to retrieve the first
  // - if any - element matching the supplied selector:
  var link = document.querySelector(

    // similarly to above, I stored the selector for the
    // relevant <a> element in the 'data-link' attribute,
    // and retrieve that attribute-value using the
    // HTMLElement.dataset interface:
    this.dataset.link
  );

  // setting the download attribute to 'true':
  link.download = true;

  // retrieving the 'data-downloadfrom'
  // attribute-value from the changed
  // radio input:
  link.href = this.dataset.downloadfrom;

  // adding the 'allowed' class to the
  // <a> element, to show that interaction
  // is now possible:
  link.classList.add('allowed');
}

// selecting all the <input> elements with name="optradio":
let radios = document.querySelectorAll('input[name=optradio]'),

    // converting that NodeList into an Array, using
    // Array.from():
    radioArray = Array.from(radios),

  // retrieving the <a> element using
  link = document.querySelector('#cvLink');

// iterating over the Array of radio-inputs using
// Array.prototype.forEach() and an Arrow function:
radioArray.forEach(

  // here we bind the linkActivate() function as the
  // event-handler for the 'change' event:
  radio => radio.addEventListener('change', linkActivate)
);

// here we bind the highlightRequirements() function as
// the event-handler for the 'mouseenter' and 'mouseleave'
// events for the <a> element:
link.addEventListener('mouseenter', highlightRequirements);
link.addEventListener('mouseleave', highlightRequirements);

function highlightRequirements(e) {
  let clicked = this,
      required = document.querySelectorAll(clicked.dataset.required);

  if (e.type === 'mouseenter') {

    if (clicked.download) {
      this.removeEventListener('mouseenter', highlightRequirements);
      this.removeEventListener('mouseleave', highlightRequirements);
      required.forEach(req => req.parentNode.classList.remove('highlight'));
    } else {
      required.forEach(req => req.parentNode.classList.add('highlight'));
    }
  } else {
    required.forEach(req => req.parentNode.classList.remove('highlight'));
  }
}

function linkActivate(e) {
  let link = document.querySelector(this.dataset.link);

  link.download = true;
  link.href = this.dataset.downloadfrom;
  link.classList.add('allowed');
}

let radios = document.querySelectorAll('input[name=optradio]'),
    radioArray = Array.from(radios),
    link = document.querySelector('#cvLink');

radioArray.forEach(
  radio => radio.addEventListener('change', linkActivate)
);

link.addEventListener('mouseenter', highlightRequirements);
link.addEventListener('mouseleave', highlightRequirements);
@keyframes highlight {
  0% {
    background-color: transparent;
  }
  75% {
    background-color: limegreen;
  }
  100% {
    background-color: transparent;
  }
}
ul + a {
  display: inline-block;
  text-align: center;
  text-decoration: none;
  margin: 0.5em auto;
}
ul + a {
  color: #66c;
  cursor: no-drop;
  border: 2px solid #66c;
  padding: 0.2em 0.4em;
  border-radius: 0.5em;
  opacity: 0.5;
}
ul + a.allowed {
  opacity: 1;
  cursor: pointer;
}
li span.highlight {
  animation: 3s highlight;
}
<div class="col-md-4 about-right">
  <ul>
    <li>
      <span class="glyphicon glyphicon-user">
      <input type="radio"class="rad" id="radio1" name="optradio" data-downloadfrom="https://drive.google.com/uc?export=download&id=MZTFCWnRYbnlvclk" data-link="#cvLink" />
      </span>Download In PDF</li>
    <li>
      <span class="glyphicon glyphicon-user">
      <input type="radio" class="rad" id="radio2" name="optradio" data-downloadfrom="https://drive.google.com/uc?export=download&id=uK6ct7MZ2N6Ni1qQUFyWXM" data-link="#cvLink" />
      </span>Download In Word Doc
    </li>
    <li>
      <span class="glyphicon glyphicon-user">
    <input type="radio" class="rad" id="radio3" name="optradio" data-downloadfrom="https://drive.google.com/uc?export=download&id=0VDenJqUldud2M" data-link="#cvLink" />
    </span>Download In HTML
    </li>
  </ul>
  <a href="#" id="cvLink" data-required="input[name=optradio]">Download CV </a>
</div>

JS Fiddle demo.

The above seems to work, though I've not verified it properly; it certainly doesn't throw any errors playing with it in the JS Fiddle demo (attached), and I think clearly shows that selecting from the radio <input> elements is required.

It seems that with the download attribute present that the download is initiated before the execution of the function you had attached via the onclick in-line event-handler (which is obtrusive JavaScript, and is why I bound events in my demo entirely in JavaScript, though I did bind a lot of data to the elements in the HTML), in this attempted solution I remove that download attribute and only add it, via JavaScript, once one of the radios is selected.