• Getting the index of a clicked element

    From James Harris@james.harris.1@gmail.com to comp.lang.javascript on Fri Jun 7 17:35:40 2019
    From Newsgroup: comp.lang.javascript

    Almost a complete beginner at JavaScript so there may be a better way to
    do this but ... what I am trying to do is have a web page consisting of
    pairs of questions and answers as in

    Question
    Answer
    Question
    Answer
    Question
    Answer

    where clicking on the question toggles whether the answer appears or
    not. Answers will initially be absent.

    I've got that bit worked out in a way I like (will explain in a separate post). My problem is in identifying the corresponding answer when a
    question is clicked.

    The web page has the form

    <div class = "question">Why?</div>
    <div class = "answer">Because</div>

    <div class = "question">When?</div>
    <div class = "answer">Soon</div>


    On DOMContentLoaded I run the following function

    function all_hide()
    {
    var answers = document.getElementsByClassName("answer");
    for (var i = 0; i < answers.length; i++)
    {
    saved_answers[i] = answers[i].innerHTML;
    answers[i].innerHTML = "";
    }
    }

    All that stuff works but what I need to add is the toggling.

    I guess that in the event handler I might be able to compare the clicked object against each element in getElementByClassName("question") until I
    find a match; then its index will be the same as that of the answer I
    have to toggle. But that could be inefficient when there are many
    questions and answers.

    My question, therefore, is how best to identify the corresponding answer
    when the user clicks on a question.

    Any suggestions?


    --
    James Harris
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From James Harris@james.harris.1@gmail.com to comp.lang.javascript on Fri Jun 7 17:59:06 2019
    From Newsgroup: comp.lang.javascript

    On 07/06/2019 17:35, James Harris wrote:
    Almost a complete beginner at JavaScript so there may be a better way to
    do this but ... what I am trying to do is have a web page consisting of
    pairs of questions and answers as in

    Question
    Answer
    Question
    Answer
    Question
    Answer

    where clicking on the question toggles whether the answer appears or
    not. Answers will initially be absent.

    So the above would initially appear as

    Question
    Question
    Question

    and users would have to click on a question to reveal the subsequent
    answer.


    I've got that bit worked out in a way I like (will explain in a separate post).

    To explain the rationale behind the choices:

    First, I want, for convenience, to be able to type the answers in
    directly under the questions to which they correspond. Since the page is intended to begin with the answers hidden that meant having them present
    but hiding them on page load.

    Second, I don't want the way to hide the text to be by making it
    invisible (e.g. by setting a CSS property) as I fear that could end up
    with the browser's 'find' function irritating the user by finding text
    the user cannot see. That's why I decided to move the InnerHTML of the
    answers to and from an array.

    Third, I want this to be compatible with many browsers and generations
    of browser so didn't want to use the data- features which I've heard are
    part of the 'ultra modern' HTML5. :-)

    Fourth, I want the web page to be usable even if the browser does not
    have JavaScript enabled. In that case, all answers would have to be
    visible all the time. Again, that meant the page having the answers
    there by default and using JavaScript, if enabled, to hide the answers
    on page load.

    That's my rationale for the basic approach. As I say, next thing is how
    to know which answer to toggle when a certain question is clicked. I
    guess this is well-trodden ground but I was evidently using the wrong
    keywords for Google to magic up an answer. Hence this query.


    --
    James Harris

    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From R.Wieser@address@not.available to comp.lang.javascript on Fri Jun 7 19:39:57 2019
    From Newsgroup: comp.lang.javascript

    James,

    I guess that in the event handler I might be able to compare the clicked object against each element in getElementByClassName("question") until I find a match;

    A match with what ? And which event handler might that be ? And what
    is started with ?

    Although you posted code that has nothing to do with your question
    (all_hide), you fully forgot(?) to post the code which you currently have
    got for the toggeling you're after. So whe have NO way to know what you
    are babbeling about when you mention "compare with". :-(

    That is ... if you already have (the first steps of) such code. Do you ?

    If not, you could do worse than to look here

    https://www.w3schools.com/jsref/event_onclick.asp

    and than especially the example starting with

    <p onclick="myFunction(this, 'red')">

    Yeah, "onclick" is the keyword. I threw it into google together with "javascript" and got the above link as the very first result. Why didn't you find that, or a comparable example yourself ? Did you at all /look/ ?

    Regards,
    Rudy Wieser


    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From Julio Di Egidio@julio@diegidio.name to comp.lang.javascript on Fri Jun 7 10:45:14 2019
    From Newsgroup: comp.lang.javascript

    On Friday, 7 June 2019 18:35:49 UTC+2, James Harris wrote:

    My problem is in identifying the corresponding answer when a
    question is clicked.

    The canonical way is the questions originally are numbered,
    then you can use element id's to refer to specific elements,
    plus you do not have the problem that any change in the structure
    of your html breaks the whole thing (IOW, you do not tie the
    functionality to the specific markup).

    <div class = "question" id="q_123">Why?</div>
    <div class = "answer" id="a_123">Because</div>

    HTH,

    Julio
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From Thomas 'PointedEars' Lahn@PointedEars@web.de to comp.lang.javascript on Fri Jun 7 20:16:07 2019
    From Newsgroup: comp.lang.javascript

    James Harris wrote:

    Almost a complete beginner at JavaScript so there may be a better way to
    do this but ... what I am trying to do is have a web page consisting of
    pairs of questions and answers as in

    Question
    Answer
    Question
    Answer
    Question
    Answer

    where clicking on the question toggles whether the answer appears or
    not. Answers will initially be absent.

    You should probably read about “event bubbling”. The event listener should
    have the following general form:

    var listener = function (event) {
    const classList = event.target.classList;

    if (classList.contains('js-question'))
    {
    if (classList.contains('shown'))
    {
    classList.remove('shown');
    }
    else
    {
    classList.add('shown');
    }
    }
    };

    Then you do the showing and hiding with CSS rules based on those CSS
    classes.

    But there is no scripting needed for this in modern graphical browsers (and text browser users want to see everything at a glance):

    HTML:

    <div class="question">
    <label for="checkbox-foo">question</label>
    <input type="checkbox" class="checkbox" id="checkbox-foo">
    <div class="answer">
    answer
    </div>
    </div>

    CSS:

    /* or whatever style you like */
    .question .checkbox { visibility: hidden; }

    .question .checkbox:not(:checked) ~ .answer { display: none; }
    .question .checkbox:checked .answer { display: block; }

    Using the :not(:checked) pseudo-class explicitly prevents the answer from being hidden if the :checked pseudo-class is not supported.

    This approach can be used for all kinds of interactive widgets, e. g. tree widgets too.

    <https://developer.mozilla.org/en-US/docs/Web/CSS/Reference#Selectors>

    If you can target HTML5 users only, then you can also use the “details” element, in which case CSS is optional:

    <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details>

    --
    PointedEars
    FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix> <https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
    Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail. --- Synchronet 3.17c-Linux NewsLink 1.110
  • From ram@ram@zedat.fu-berlin.de (Stefan Ram) to comp.lang.javascript on Fri Jun 7 18:20:24 2019
    From Newsgroup: comp.lang.javascript

    James Harris <james.harris.1@gmail.com> writes:
    where clicking on the question toggles whether the answer appears or
    not. Answers will initially be absent.
    I've got that bit worked out in a way I like (will explain in a separate >post). My problem is in identifying the corresponding answer when a
    question is clicked.

    Tested under a recent "Firefox":

    main.html

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
    <head><meta charset="UTF-8" />
    <title>Q and A</title><style type="text/css">

    hide { display: none }

    </style></head><body>


    <dl class="question">
    <dt>question</dt><dd>What is 1+1?</dd></dl>
    <dl class="answer">
    <dt>answer</dt><dd>2</dd></dl>
    </ul>

    <dl class="question">
    <dt>question</dt><dd>What is 4-1?</dd></dl>
    <dl class="answer">
    <dt>answer</dt><dd>3</dd></dl>
    </ul>

    <pre><code><script>/*<![CDATA[*/

    [].map.call
    ( document.getElementsByClassName( "answer" ),
    answer => answer.classList.add( "hide" ));

    [].map.call
    ( document.getElementsByClassName( "question" ),
    question => question.addEventListener
    ( "click",
    event =>
    event.currentTarget.parentNode.lastElementChild.classList.toggle
    ( "hide" )))

    /*]]>*/</script></code></pre></body></html>



    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From Thomas 'PointedEars' Lahn@PointedEars@web.de to comp.lang.javascript on Fri Jun 7 20:33:36 2019
    From Newsgroup: comp.lang.javascript

    James Harris wrote:

    To explain the rationale behind the choices:

    Your design choices appear to be driven mostly by ignorance and
    misconceptions about Web development and Web browsers. A recipe for
    disaster.

    First, I want, for convenience, to be able to type the answers in
    directly under the questions to which they correspond. Since the page is intended to begin with the answers hidden that meant having them present
    but hiding them on page load.

    It is not a good idea to manipulate the document tree on page load as that will slow down rendering. Hiding elements is OK, changing their content in most cases (and certainly in this one) is not.

    Second, I don't want the way to hide the text to be by making it
    invisible (e.g. by setting a CSS property) as I fear that could end up
    with the browser's 'find' function irritating the user by finding text
    the user cannot see.

    Working browsers will not let users “Find” content that have style “display:
    none” or HTML5’s “hidden” attribute set.

    Third, I want this to be compatible with many browsers and generations
    of browser so didn't want to use the data- features which I've heard are
    part of the 'ultra modern' HTML5. :-)

    For suitable values for “ultra modern”. HTML5 is best current practice since almost 5 years ago – an eternity on the Web. The current W3C Recommendation is HTML 5.2 of 2017, work on HTML 5.3 is in progress.

    Be aware that using scripting instead of plain HTML and CSS already
    sacrifices some compatibility.

    Fourth, I want the web page

    “Where we are developing, there are no "web pages".”¹

    _______
    ¹ apologies to Robert Zemeckis
    --
    PointedEars
    FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix> <https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
    Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail. --- Synchronet 3.17c-Linux NewsLink 1.110
  • From Thomas 'PointedEars' Lahn@PointedEars@web.de to comp.lang.javascript on Fri Jun 7 20:36:23 2019
    From Newsgroup: comp.lang.javascript

    Stefan Ram wrote:

    Tested under a recent "Firefox":

    main.html

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head><meta charset="UTF-8" />
    <title>Q and A</title><style type="text/css">

    hide { display: none }

    </style></head><body>


    <dl class="question">
    <dt>question</dt><dd>What is 1+1?</dd></dl>
    <dl class="answer">
    <dt>answer</dt><dd>2</dd></dl>
    </ul>

    <dl class="question">
    <dt>question</dt><dd>What is 4-1?</dd></dl>
    <dl class="answer">
    <dt>answer</dt><dd>3</dd></dl>
    </ul>

    <pre><code><script>/*<![CDATA[*/

    [].map.call
    ( document.getElementsByClassName( "answer" ),
    answer => answer.classList.add( "hide" ));

    [].map.call
    ( document.getElementsByClassName( "question" ),
    question => question.addEventListener
    ( "click",
    event =>
    event.currentTarget.parentNode.lastElementChild.classList.toggle
    ( "hide" )))

    JFTR (I know from experience that it is futile to tell Stefan Ram anything):

    This is NOT remotely how proper code looks like. If you would be employed
    in the industry, you would probably get disciplined or fired for this.

    --
    PointedEars
    FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix> <https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
    Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail. --- Synchronet 3.17c-Linux NewsLink 1.110
  • From Thomas 'PointedEars' Lahn@PointedEars@web.de to comp.lang.javascript on Fri Jun 7 22:48:26 2019
    From Newsgroup: comp.lang.javascript

    Thomas 'PointedEars' Lahn wrote:

    But there is no scripting needed for this in modern graphical browsers
    (and text browser users want to see everything at a glance):

    HTML:

    <div class="question">
    <label for="checkbox-foo">question</label>
    <input type="checkbox" class="checkbox" id="checkbox-foo">
    <div class="answer">
    answer
    </div>
    </div>

    CSS:

    /* or whatever style you like */
    .question .checkbox { visibility: hidden; }

    .question .checkbox:not(:checked) ~ .answer { display: none; }
    .question .checkbox:checked .answer { display: block; }

    Minor mistake: This line should be

    .question .checkbox:checked ~ .answer { display: block; }

    to select elements whose “class” attribute contains the class name “answer”
    that are also siblings following the checkbox.

    Using the :not(:checked) pseudo-class explicitly prevents the answer from being hidden if the :checked pseudo-class is not supported.

    This approach can be used for all kinds of interactive widgets, e. g. tree widgets too.

    <https://developer.mozilla.org/en-US/docs/Web/CSS/Reference#Selectors>

    --
    PointedEars
    FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix> <https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
    Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail. --- Synchronet 3.17c-Linux NewsLink 1.110
  • From JJ@jj4public@vfemail.net to comp.lang.javascript on Sat Jun 8 12:57:29 2019
    From Newsgroup: comp.lang.javascript

    On Fri, 7 Jun 2019 17:35:40 +0100, James Harris wrote:

    Almost a complete beginner at JavaScript so there may be a better way to
    do this but ... what I am trying to do is have a web page consisting of pairs of questions and answers as in

    Question
    Answer
    Question
    Answer
    Question
    Answer

    where clicking on the question toggles whether the answer appears or
    not. Answers will initially be absent.

    I've got that bit worked out in a way I like (will explain in a separate post). My problem is in identifying the corresponding answer when a
    question is clicked.

    The web page has the form

    <div class = "question">Why?</div>
    <div class = "answer">Because</div>

    <div class = "question">When?</div>
    <div class = "answer">Soon</div>

    On DOMContentLoaded I run the following function

    function all_hide()
    {
    var answers = document.getElementsByClassName("answer");
    for (var i = 0; i < answers.length; i++)
    {
    saved_answers[i] = answers[i].innerHTML;
    answers[i].innerHTML = "";
    }
    }

    All that stuff works but what I need to add is the toggling.

    I guess that in the event handler I might be able to compare the clicked object against each element in getElementByClassName("question") until I find a match; then its index will be the same as that of the answer I
    have to toggle. But that could be inefficient when there are many
    questions and answers.

    My question, therefore, is how best to identify the corresponding answer when the user clicks on a question.

    Any suggestions?

    With that HTML structure, you can setup the click event handler like below.

    addEventListener("click", e => {
    e = e.target;
    if (e.classList.contains("question")) {
    e = e.nextElementSibling.style;
    e.display = e.display ? "" : "block";
    }
    });
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From dr.j.r.stockton@dr.j.r.stockton@gmail.com to comp.lang.javascript on Sat Jun 8 01:43:17 2019
    From Newsgroup: comp.lang.javascript

    On Friday, 7 June 2019 19:33:45 UTC+1, Thomas 'PointedEars' Lahn wrote:

    It is not a good idea to manipulate the document tree on page load as that will slow down rendering. Hiding elements is OK, changing their content in most cases (and certainly in this one) is not.

    Rendering is so quick on modern computers hat, for pages of reasonable size, worrying about its speed is pointless (likely exception : pages with too many large images, or with complex looping calculation that must be re-done of re-rendering).

    --
    PointedEars
    FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix> <https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
    Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From dr.j.r.stockton@dr.j.r.stockton@gmail.com to comp.lang.javascript on Sat Jun 8 02:16:13 2019
    From Newsgroup: comp.lang.javascript

    On Friday, 7 June 2019 17:35:49 UTC+1, James Harris wrote:
    Almost a complete beginner at JavaScript so there may be a better way to
    do this but ... what I am trying to do is have a web page consisting of pairs of questions and answers as in

    Question
    Answer
    Question
    Answer
    Question
    Answer

    where clicking on the question toggles whether the answer appears or
    not. Answers will initially be absent.

    By which you probably mean invisible.


    The web page has the form

    <div class = "question">Why?</div>
    <div class = "answer">Because</div>

    <div class = "question">When?</div>
    <div class = "answer">Soon</div>


    My question, therefore, is how best to identify the corresponding answer when the user clicks on a question.

    Any suggestions?

    The following is pseudo-code :-

    Class "answer" should style its element as unshown.

    All of class "question" should have, written in the HTML or added by on-load script, onclick = X(this) where X is a function defined like

    function X(T) { T.nextSibling.style.shown = not-what-it was }

    It will be necessary to loop through nextSiblings to find the first "answer", if it is possible that there may be another element between the 'div's.


    Better, maybe, to use

    <div class = "question">Why?
    <div class = "answer">Because</div>
    </div>

    to bind the answer more closely to the question.

    You could finish the question with a button, of value in ["?", "X"], and with button onclick toggling the button value and the shown-ness of the answer. That explains what the user needs to do.

    Here is an on-off button, not connected
    <input type="button" value=0 onclick="this.value^=1"> // Tested.

    Connect it, maybe, by
    <input type="button" value=0 onclick="THAT = (this.value^=1 ? A : B)"> // .


    --
    (c) John Stockton, near London, UK. Using Google Groups. |
    Mail: J.R.""""""""@physics.org - or as Reply-To, if any. |
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From James Harris@james.harris.1@gmail.com to comp.lang.javascript on Sat Jun 8 10:30:14 2019
    From Newsgroup: comp.lang.javascript

    On 08/06/2019 06:57, JJ wrote:
    On Fri, 7 Jun 2019 17:35:40 +0100, James Harris wrote:

    ...

    <div class = "question">Why?</div>
    <div class = "answer">Because</div>

    <div class = "question">When?</div>
    <div class = "answer">Soon</div>

    ...

    With that HTML structure, you can setup the click event handler like below.

    addEventListener("click", e => {
    e = e.target;
    if (e.classList.contains("question")) {
    e = e.nextElementSibling.style;
    e.display = e.display ? "" : "block";
    }
    });


    Good answer.

    Were there any browsers which supported JavaScript but not the .style property?

    FWIW I got the system to work as I want it to. The complete code is
    below. Your answer may be better but I quite like what I came up with.

    I am not familiar with JavaScript so folks reading the code may find
    things they don't like or which could be better. Feel free to criticise
    it. Note that I avoided nextElementSibling for compatibility.


    <script type = "text/javascript">

    /**********************************************************************
    *
    * Globals
    *
    **********************************************************************/

    var saved_answers = []; //Answers saved from the HTML
    var BLANK_ANSWER = ""; //The inner HTML to use when answer missing
    var QCLASS = "question"; //The element class to use for questions
    var ACLASS = "answer"; //The element class to use for answers
    var QID = "Q-"; //The prefix to set on question ids



    /**********************************************************************
    *
    * Hide all the answers (if JavaScript is supported)
    *
    **********************************************************************/

    function all_hide()
    {
    var targ;
    var i = 0;
    var questions = document.getElementsByClassName(QCLASS);
    for (question of questions)
    {
    targ = next_sibling(question, Node.ELEMENT_NODE);
    if (targ && targ.className === ACLASS)
    {
    question.id = QID + i;
    saved_answers[question.id] = targ.innerHTML;
    targ.innerHTML = BLANK_ANSWER;
    i++;
    }
    }
    }



    /**********************************************************************
    *
    * Make each question clickable
    *
    **********************************************************************/

    function questions_make_clickable()
    {
    var questions = document.getElementsByClassName(QCLASS);
    for (question of questions)
    {
    question.addEventListener("click", qclick);
    }
    }



    /**********************************************************************
    *
    * Find the next sibling of a specified type. Use this in preference to
    * nextElementSibling if wanting compatibility with browsers which do
    * not support that function.
    *
    **********************************************************************/

    function next_sibling(from, node_type)
    {
    var targ = from;
    do
    {
    targ = targ.nextSibling;
    }
    while (targ && targ.nodeType !== node_type);
    return targ;
    }



    /**********************************************************************
    *
    * Respond to a click on a question
    *
    **********************************************************************/

    function qclick(ev)
    {
    var targ = next_sibling(ev.target, Node.ELEMENT_NODE);
    if (targ && targ.className === ACLASS)
    {
    // Toggle the answer
    if (targ.innerHTML === BLANK_ANSWER)
    {
    targ.innerHTML = saved_answers['' + ev.target.id];
    }
    else
    {
    targ.innerHTML = BLANK_ANSWER;
    }
    }
    }



    /**********************************************************************
    *
    * Code to run on page load
    *
    **********************************************************************/

    window.addEventListener(
    'DOMContentLoaded', (event) =>
    {
    all_hide();
    questions_make_clickable();
    }
    );

    </script>


    --
    James Harris
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From Thomas 'PointedEars' Lahn@PointedEars@web.de to comp.lang.javascript on Sat Jun 8 12:13:02 2019
    From Newsgroup: comp.lang.javascript

    James Harris wrote:

    On 08/06/2019 06:57, JJ wrote:
    On Fri, 7 Jun 2019 17:35:40 +0100, James Harris wrote:
    <div class = "question">Why?</div>
    <div class = "answer">Because</div>

    <div class = "question">When?</div>
    <div class = "answer">Soon</div>

    With that HTML structure, you can setup the click event handler like
    below.

    addEventListener("click", e => {

    addEventListener must be called as method of the event target, not the
    global object.

    e = e.target;
    if (e.classList.contains("question")) {

    This is actually insufficient, see below.

    e = e.nextElementSibling.style;
    e.display = e.display ? "" : "block";

    Looking for siblings with script code and writing CSSOM code is unnecessary
    if you use the sibling *element* selector(s) of CSS with attached CSS rules. The latter is also much easier to maintain and less error-prone (a sibling *node* can be a text node, and text nodes do not have a “style” property; as
    a result, a TypeError exception is thrown on this line then).

    In that regard, my code needs to be improved slightly so that it checks whether, if the object in question does not have a “classList” property (is
    not an element node), one of its ancestors has and its “class” attribute contains the pertinent class name. There is this trade-off with event bubbling to find out the proper ancestor if a descendant was the event
    target; this problem does not exist if event listeners are being added to
    the proper ancestors directly, but then it has to be added to every single
    one of them. Insofar using event bubbling this way might actually not
    always be the best strategy (speed tests pending; it is also situation- dependent).

    }
    });


    Good answer.

    Rest assured that as a beginner you are not in any position to tell.

    It is a striking feature of ECMAScript-based programming languages and their applications in particular that, because they seem comparably easy to learn, people very quickly become overconfident in their estimations of their own knowledge about them. Some of them even take their hubris to writing more
    or less clueless books (Flanagan, Crockford, Resig). There is a culture of cargo cult programming. Blind leading the blind.

    A quote (ignoring the wrong spelling, indication overgeneralization):

    | > If you get a bunch of authors […] that state the same "best practices"
    | > in any programming language, then you can bet who is wrong or right...
    | Not with javascript. Nonsense propagates like wildfire in this field.
    | -- Richard Cornford, comp.lang.javascript, 2011-11-14

    Were there any browsers which supported JavaScript but not the .style property?

    Yes.

    FWIW I got the system to work as I want it to. The complete code is
    below. Your answer may be better but I quite like what I came up with.

    Whether *you* *like* it does NOT matter. It must *work* for the *customer/user*. That is the first rule of software development,
    in particular of Web development where you have almost no idea
    where and under which circumstances your code is going to run.

    I am not familiar with JavaScript so folks reading the code may find
    things they don't like or which could be better.

    Again, it is not a matter of “like”. There are valid *reasons* why it is being recommended to do some things one way and not the other ways.

    Feel free to criticise it.

    Thanks, but no, thanks. I have told you how to do this easily, efficiently, and in a backwards-compatible way. You decided to do it hopelessly complicated, inefficient, and in an incompatible way instead. Now you have
    to live with the consequences.

    [convuluted mess]

    --
    PointedEars
    FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix> <https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
    Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail. --- Synchronet 3.17c-Linux NewsLink 1.110
  • From John G Harris@niam@jghnorth.org.uk.invalid to comp.lang.javascript on Sat Jun 8 13:35:54 2019
    From Newsgroup: comp.lang.javascript

    On Sat, 08 Jun 2019 12:13:02 +0200, Thomas 'PointedEars' Lahn <PointedEars@web.de> wrote:

    <snip>
    It is a striking feature of ECMAScript-based programming languages and their >applications in particular that, because they seem comparably easy to learn, >people very quickly become overconfident in their estimations of their own >knowledge about them. Some of them even take their hubris to writing more >or less clueless books (Flanagan, Crockford, Resig).
    <snip>

    Hallelujah! Thomas agrees with me about Crockford. (See one of the few
    book reviews in this news group).

    John
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From John G Harris@niam@jghnorth.org.uk.invalid to comp.lang.javascript on Sat Jun 8 13:45:21 2019
    From Newsgroup: comp.lang.javascript

    On Sat, 08 Jun 2019 12:13:02 +0200, Thomas 'PointedEars' Lahn <PointedEars@web.de> wrote:

    <snip>
    Whether *you* *like* it does NOT matter. It must *work* for the >*customer/user*. That is the first rule of software development,
    in particular of Web development where you have almost no idea
    where and under which circumstances your code is going to run.
    <snip>

    An experienced programmer who mutated into quality control told me
    about a particular product Release Candidate :

    She :
    "Look what happens when a User does *this*."
    Program goes SPLAT!

    Programmer :
    "Why would anyone do *that*?"

    She :
    "I don't know, but they do!"

    John
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From James Harris@james.harris.1@gmail.com to comp.lang.javascript on Sat Jun 8 18:52:32 2019
    From Newsgroup: comp.lang.javascript

    On 07/06/2019 18:39, R.Wieser wrote:
    James,

    I guess that in the event handler I might be able to compare the clicked
    object against each element in getElementByClassName("question") until I
    find a match;

    A match with what ? And which event handler might that be ? And what
    is started with ?

    Although you posted code that has nothing to do with your question (all_hide), you fully forgot(?) to post the code which you currently have
    got for the toggeling you're after. So whe have NO way to know what you
    are babbeling about when you mention "compare with". :-(

    That is ... if you already have (the first steps of) such code. Do you ?

    That's OK. I've got it working. Full initial code posted at https://groups.google.com/d/msg/comp.lang.javascript/yOMha0ZBCeg/HGbOPxkWBgAJ.




    --
    James Harris

    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From James Harris@james.harris.1@gmail.com to comp.lang.javascript on Sat Jun 8 18:57:01 2019
    From Newsgroup: comp.lang.javascript

    On 07/06/2019 18:45, Julio Di Egidio wrote:
    On Friday, 7 June 2019 18:35:49 UTC+2, James Harris wrote:

    My problem is in identifying the corresponding answer when a
    question is clicked.

    The canonical way is the questions originally are numbered,
    then you can use element id's to refer to specific elements,
    plus you do not have the problem that any change in the structure
    of your html breaks the whole thing (IOW, you do not tie the
    functionality to the specific markup).

    <div class = "question" id="q_123">Why?</div>
    <div class = "answer" id="a_123">Because</div>

    I didn't want to put the user through the hassle of having to assign
    unique ids but I used your idea to generate the ids automatically with

    var questions = document.getElementsByClassName(QCLASS);

    // Go through each question
    for (question of questions)
    {
    // Find the following answer
    targ = next_sibling(question, Node.ELEMENT_NODE);
    if (targ && targ.className === ACLASS)
    {
    // Give the question a unique id
    question.id = QID + i;

    Then the id is used as a key to save the answer text in an array with

    // Move the answer out of the div into the designated array
    saved_answers[question.id] = targ.innerHTML;
    targ.innerHTML = BLANK_ANSWER;

    // Next id number
    i++;
    }
    }



    --
    James Harris
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From James Harris@james.harris.1@gmail.com to comp.lang.javascript on Sat Jun 8 19:03:54 2019
    From Newsgroup: comp.lang.javascript

    On 08/06/2019 11:13, Thomas 'PointedEars' Lahn wrote:
    James Harris wrote:

    ...

    Were there any browsers which supported JavaScript but not the .style
    property?

    Yes.

    In that case I am right to design the system as I have: To use
    JavaScript for processing (including the 'hiding' of answers), and to
    use CSS purely for appearance.


    FWIW I got the system to work as I want it to. The complete code is
    below. Your answer may be better but I quite like what I came up with.

    Whether *you* *like* it does NOT matter. It must *work* for the *customer/user*. That is the first rule of software development,
    in particular of Web development where you have almost no idea
    where and under which circumstances your code is going to run.

    As the user of it, I like it.


    I am not familiar with JavaScript so folks reading the code may find
    things they don't like or which could be better.

    Again, it is not a matter of “like”. There are valid *reasons* why it is being recommended to do some things one way and not the other ways.

    Feel free to criticise it.

    Thanks, but no, thanks. I have told you how to do this easily, efficiently, and in a backwards-compatible way. You decided to do it hopelessly complicated, inefficient, and in an incompatible way instead. Now you have to live with the consequences.

    [convuluted mess]

    It's clear, easy to read, separates concepts, is written to cope with
    multiple browsers and browser settings, and should be fast. That's far
    from a 'mess'. I'd call it a good solution.


    --
    James Harris

    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From James Harris@james.harris.1@gmail.com to comp.lang.javascript on Sat Jun 8 19:14:43 2019
    From Newsgroup: comp.lang.javascript

    On 08/06/2019 10:16, dr.j.r.stockton@gmail.com wrote:
    On Friday, 7 June 2019 17:35:49 UTC+1, James Harris wrote:
    Almost a complete beginner at JavaScript so there may be a better way to
    do this but ... what I am trying to do is have a web page consisting of
    pairs of questions and answers as in

    Question
    Answer
    Question
    Answer
    Question
    Answer

    where clicking on the question toggles whether the answer appears or
    not. Answers will initially be absent.

    By which you probably mean invisible.


    The web page has the form

    <div class = "question">Why?</div>
    <div class = "answer">Because</div>

    <div class = "question">When?</div>
    <div class = "answer">Soon</div>


    My question, therefore, is how best to identify the corresponding answer
    when the user clicks on a question.

    Any suggestions?

    The following is pseudo-code :-

    Class "answer" should style its element as unshown.

    All of class "question" should have, written in the HTML or added by on-load script, onclick = X(this) where X is a function defined like

    function X(T) { T.nextSibling.style.shown = not-what-it was }

    It will be necessary to loop through nextSiblings to find the first "answer", if it is possible that there may be another element between the 'div's.

    That's what I have done. As some browsers don't have nextElementSibling
    I wrote a simple function to iterate through the siblings until it gets
    the next Element or whatever type.

    function next_sibling(from, node_type)
    {
    var targ = from;

    // Iterate over the following siblings until we get to one which
    // has the requested type.
    do
    {
    targ = targ.nextSibling;
    }
    while (targ && targ.nodeType !== node_type);

    return targ;
    }




    Better, maybe, to use

    <div class = "question">Why?
    <div class = "answer">Because</div>
    </div>

    to bind the answer more closely to the question.

    I thought about that. It may have helped. But I went with keeping them separate. Having the two divs as

    <div class = "question">Why?</div>
    <div class = "answer">Because</div>

    if ev is the event as seen in the onclick handler then

    var targ = next_sibling(ev.target, Node.ELEMENT_NODE);

    gets from the question to the following answer using the function, above.


    You could finish the question with a button, of value in ["?", "X"], and with button onclick toggling the button value and the shown-ness of the answer. That explains what the user needs to do.

    Here is an on-off button, not connected
    <input type="button" value=0 onclick="this.value^=1"> // Tested.

    Connect it, maybe, by
    <input type="button" value=0 onclick="THAT = (this.value^=1 ? A : B)"> // .

    Yes, I'm not sure about styling. Have started a separate thread about
    that but just for info I found this 'accordion' idea which looks quite
    clever.

    https://www.w3schools.com/howto/howto_js_accordion.asp


    --
    James Harris
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From Thomas 'PointedEars' Lahn@PointedEars@web.de to comp.lang.javascript on Sat Jun 8 21:11:01 2019
    From Newsgroup: comp.lang.javascript

    James Harris wrote:

    On 08/06/2019 11:13, Thomas 'PointedEars' Lahn wrote:
    James Harris wrote:
    Were there any browsers which supported JavaScript but not the .style
    property?
    Yes.

    Actually, “No”, because the existence of the “style” *property* more or less
    requires an ECMAScript-based runtime environment. The correct answer is “Yes” for the “style” _element_ and style _attribute_.

    Also note that the answer made no indication as to whether the question made sense.

    In that case I am right to design the system as I have:

    No.

    FWIW I got the system to work as I want it to. The complete code is
    below. Your answer may be better but I quite like what I came up with.

    Whether *you* *like* it does NOT matter. It must *work* for the
    *customer/user*. That is the first rule of software development,
    in particular of Web development where you have almost no idea
    where and under which circumstances your code is going to run.

    As the user of it, I like it.

    Pardon? If you are the only user, why did *you* talk about backwards compatibility?

    [[convoluted mess]]

    It's clear, easy to read, separates concepts, is written to cope with multiple browsers and browser settings, and should be fast. That's far
    from a 'mess'. I'd call it a good solution.

    You have no idea. Globals? Loops (even with for…of)? innerHTML?

    <https://github.com/airbnb/javascript>

    --
    PointedEars
    FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix> <https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
    Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail. --- Synchronet 3.17c-Linux NewsLink 1.110
  • From dr.j.r.stockton@dr.j.r.stockton@gmail.com to comp.lang.javascript on Sat Jun 8 14:18:58 2019
    From Newsgroup: comp.lang.javascript

    On Saturday, 8 June 2019 20:11:09 UTC+1, Thomas 'PointedEars' Lahn wrote:
    James Harris wrote:

    On 08/06/2019 11:13, Thomas 'PointedEars' Lahn wrote:
    James Harris wrote:
    Were there any browsers which supported JavaScript but not the .style
    property?
    Yes.

    Actually, “No”, because the existence of the “style” *property* more or less
    requires an ECMAScript-based runtime environment.
    Nonsense.
    (1.1) I have pages which use CSS styles which are set in the source HTML file and are never changed after loading. I don't think I've ever set or changed the float property after loading, and I don't recall dynamically altering margins or padding either.
    (1.2) Internet Explorer supports <script type="text/vbscript"> and VBScript is not ECMAScript-based. I expect that VBscript can manipulate CSS styles.
    (1.3) Anyone who can write an HTML engine could, for example, support <script type="text/fortran"> and <script type="text/algol68">.
    (2) He was in essence asking "does script require style" but you have answered "does style require script".
    For some while, I was using JScript without knowing of the existence of style. --
    (c) John Stockton, near London, UK. Using Google Groups. |
    Mail: J.R.""""""""@physics.org - or as Reply-To, if any. |
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From Julio Di Egidio@julio@diegidio.name to comp.lang.javascript on Sun Jun 9 05:44:58 2019
    From Newsgroup: comp.lang.javascript

    On Saturday, 8 June 2019 19:57:11 UTC+2, James Harris wrote:
    On 07/06/2019 18:45, Julio Di Egidio wrote:
    On Friday, 7 June 2019 18:35:49 UTC+2, James Harris wrote:

    My problem is in identifying the corresponding answer when a
    question is clicked.

    The canonical way is the questions originally are numbered,
    then you can use element id's to refer to specific elements,
    plus you do not have the problem that any change in the structure
    of your html breaks the whole thing (IOW, you do not tie the
    functionality to the specific markup).

    <div class = "question" id="q_123">Why?</div>
    <div class = "answer" id="a_123">Because</div>

    I didn't want to put the user through the hassle of having to assign
    unique ids but I used your idea to generate the ids automatically with

    var questions = document.getElementsByClassName(QCLASS);

    // Go through each question
    for (question of questions)
    {
    // Find the following answer
    targ = next_sibling(question, Node.ELEMENT_NODE);
    if (targ && targ.className === ACLASS)
    {
    // Give the question a unique id
    question.id = QID + i;

    Then the id is used as a key to save the answer text in an array with

    // Move the answer out of the div into the designated array
    saved_answers[question.id] = targ.innerHTML;
    targ.innerHTML = BLANK_ANSWER;

    // Next id number
    i++;
    }
    }

    Of course you would not eventually write it by hand, the data usually comes from a database or some other source and the page or parts of it are generated or loaded dynamically: it just goes without saying, plus it's a separate logical stage, i.e. you can start by mocking by hand and later go to automatically generated.

    You then do a completely pointless operation there, as once you have found the elements, you just don't need *at that point* to set and keep id's, you already have the references and would just keep those.

    Overall, you and the whole band-wagon here just have no idea what you are doing: indeed you keep missing the *one critical point* here, which is do not tie your logic to the markup!

    HTH,

    Julio
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From dr.j.r.stockton@dr.j.r.stockton@gmail.com to comp.lang.javascript on Mon Jun 10 11:29:31 2019
    From Newsgroup: comp.lang.javascript

    On Friday, 7 June 2019 17:35:49 UTC+1, James Harris wrote:
    Almost a complete beginner at JavaScript so there may be a better way to
    do this but ... what I am trying to do is have a web page consisting of pairs of questions and answers as in

    Question
    Answer
    Question
    Answer
    Question
    Answer

    where clicking on the question toggles whether the answer appears or
    not. Answers will initially be absent.

    I've got that bit worked out in a way I like (will explain in a separate post). My problem is in identifying the corresponding answer when a
    question is clicked.

    The web page has the form

    <div class = "question">Why?</div>
    <div class = "answer">Because</div>

    <div class = "question">When?</div>
    <div class = "answer">Soon</div>
    ...
    Apart from layout, the following achieves what I think you want to achieve.
    As is, the two TD elements in each TR *must* be adjacent enough for the single nextSibling to work. If you want a different layout, it should only be necessary for the layout within each Q-A pair to be exactly the same, and you can then, onclick, program the needed moves within the DOM tree.
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <title>Test for Q+A problem</title>
    <style type="text/css"> .B { visibility: hidden; } </style>
    <script>
    function F(T) { var S = T.nextSibling.style
    S.visibility = (S.visibility=="visible" ? "hidden" : "visible")
    }
    </script>
    </head>
    <body>
    <table summary=Test border=1>
    <caption>Click Question to toggle Answer</caption>
    <tr><td onclick="F(this)">Q1</td><td class=B>A1</td></tr>
    <tr><td onclick="F(this)">Q2</td><td class=B>A2</td></tr>
    </table>
    </body>
    </html>
    --
    (c) John Stockton, near London, UK. Using Google Groups. |
    Mail: J.R.""""""""@physics.org - or as Reply-To, if any. |
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From Evertjan.@exxjxw.hannivoort@inter.nl.net to comp.lang.javascript on Mon Jun 10 23:00:24 2019
    From Newsgroup: comp.lang.javascript

    dr.j.r.stockton@gmail.com wrote on 10 Jun 2019 in comp.lang.javascript:

    S.visibility = (S.visibility=="visible" ? "hidden" : "visible")

    Parenteses in error!

    var S = T.nextSibling.style;
    S.visibility = (S.visibility == "visible") ? "hidden" : "visible";


    --
    Evertjan.
    The Netherlands.
    (Please change the x'es to dots in my emailaddress)
    --- Synchronet 3.17c-Linux NewsLink 1.110
  • From dr.j.r.stockton@dr.j.r.stockton@gmail.com to comp.lang.javascript on Tue Jun 11 03:22:22 2019
    From Newsgroup: comp.lang.javascript

    On Monday, 10 June 2019 22:00:31 UTC+1, Evertjan. wrote:
    JRS wrote on 10 Jun 2019 in comp.lang.javascript:

    S.visibility = (S.visibility=="visible" ? "hidden" : "visible")

    Parenteses in error!

    var S = T.nextSibling.style;
    S.visibility = (S.visibility == "visible") ? "hidden" : "visible";

    Neither my parentheses nor yours are needed, at least in current Firefox and Edge. But your "Parenteses" is in error!

    As coded, of course, while the answer is toggled between visible and invisible, the space for the answers is permanently visible. If the space is also to be toggled, the OP should use 'display' ("block"/"none", IIRC) instead of 'visibility'.

    So, ...

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <title>Test for Q+A problem</title>
    <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">

    <style type="text/css">
    .A { background : lightblue; }
    .B { visibility: hidden; background : lightgreen; }
    .C { display: none; background : lightgreen; }
    </style>

    <script>

    function F(T) { var S = T.nextSibling.style
    S.visibility = S.visibility=="visible" ? "hidden" : "visible"
    }

    function G(T) { var S = T.nextSibling.style
    S.display = S.display=="block" ? "none" : "block"
    }

    </script>

    </head>
    <body>

    <table summary=Test border=1>
    <caption>Click Question to toggle Answer</caption>
    <tr><td class=A onclick="F(this)">Q1</td><td class=B>A1</td></tr>
    <tr><td class=A onclick="F(this)">Q2</td><td class=B>A2</td></tr>
    </table>

    <ul style="list-style-type: none;">
    <li class=A onclick="F(this)">Q3</li><li class=B>A3</li>
    <li class=A onclick="F(this)">Q4</li><li class=B>A4</li>
    </ul>

    <ul style="list-style-type: none;">
    <li class=A onclick="G(this)">Q5</li><li class=C>A5</li>
    <li class=A onclick="G(this)">Q6</li><li class=C>A6</li>
    </ul>

    </body>
    </html>

    --
    (c) John Stockton, near London, UK. Using Google Groups. |
    Mail: J.R.""""""""@physics.org - or as Reply-To, if any. |
    --- Synchronet 3.17c-Linux NewsLink 1.110