tags:

views:

68

answers:

2

On my forum-based website, I have a link below every post for reporting spam or abuse. Whenever this link is clicked, a web service is called on the server, when the call returns, the span containing the link (see the code below) is updated with something like 'Post reported' or if an error occurs it shows something like 'An error occurred while reporting the post', this is the javascript code:

<script src="/js/MicrosoftAjax.js" type="text/javascript" language="javascript"></script>

<script type="text/javascript" language="javascript">

    var spanToUpdate;

    function ReportPost(updateSpan, postID)
    {
      if (confirm("Are you sure you want to report this post as spam or abuse?"))
      {
        spanToUpdate = updateSpan;
        var proxy = SiteWS.ReportPost(postID, onReportPostSuccess, onReportPostFailure);
      }
    }

    function onReportPostSuccess(sender, e)
    {
      spanToUpdate.innerHTML = "Post reported";
    }

    function onReportPostFailure(sender, e)
    {
      spanToUpdate.innerHTML = "An error occurred while reporting the post";
    }

</script>

And this is the reporting link:

<div class="post">
  <p>post text here</p>
  <span><a href="#" onclick="ReportPost(this.parentNode, <%= post.ID %>);return false;" title="Report spam or abuse">Report Post</a></span>
</div>

Other posts ...

As you can see, I use a variable, spanToUpdate, to hold a reference to the span that contains the reporting link, which means that if the user reports another post (ie. clicks another reporting link) before the call returns, the span of the last post will be updated twice and the previous one won't be updated at all, is there any workaround for this?

Many thanks

+3  A: 

You can use anonymous functions and closures for that.

function ReportPost(updateSpan, postID) {
  if (confirm("Are you sure you want to report this post as spam or abuse?")) {
    var proxy = SiteWS.ReportPost(
      postID,
      function(sender,e) {updateSpan.innerHTML = "Post reported" },
      function(sender,e) {updateSpan.innerHTML = "An error occurred while reporting the post" }
    );
  }
}

edit:

hmm .. just wondering, will updateSpan be referring to the same span when the anonymous method is called? – Waleed Eissa
Yes, that's the magic of closures. Try this little example:
<head>
  <script>
    function foo()
    {
      bar(1, 100);
      bar(2, 150);
      bar(3, 200);
      bar(4, 250);
      bar(5, 300);
      document.getElementById("div1").innerHTML += "foo() is done. ";
      return;
    }
    function bar(val, timeout) {
      window.setTimeout(
        function() {
          document.getElementById("div1").innerHTML += " " + val + " ";
        },
        timeout
      );
    }
  </script>
</head>
<body>
  <button onclick="foo()">click</button>
  <div id="div1"></div>
</body>
You will see that each time the anonymous function is called it has preserved "its own" value of val from the time/context when bar() was called.

VolkerK
+1 This seems like a good idea, I'm going to try this .. thanks
Waleed Eissa
hmm .. just wondering, will updateSpan be referring to the same span when the anonymous method is called?
Waleed Eissa
If you declare updateSpan scoped inside the function that creates the closure, then yes: it will keep the value from when the closure was created, even if the surrounding function is called again.
Anonymous
Never heard of closures before today, obviously there's so much for me to learn about Javascript, thanks a lot for your great answer
Waleed Eissa
A: 

Not a JavaScript developer so this might not work. Would it be possible to hold a reference to the post id and the spanToUpdate and then have the response from the server include the post id. Then you could retrieve the correct spanToUpdate.

willcodejavaforfood
I believe this is possible, but I still prefer to do it in JS (if possible), so I'll leave this as a last resort ...
Waleed Eissa