Extract lines under the specified heading I wrote the following working code, which I just can't stomach:

var data = [
    { id: 0, isHeading: true, description: "A heading" },
    { id: 1, isHeading: false, description: "Blah 1" },
    { id: 2, isHeading: false, description: "Blah 2" },
    { id: 3, isHeading: true, description: "A heading" },
    { id: 4, isHeading: false, description: "Blah 3" },
    { id: 5, isHeading: false, description: "Blah 4" },
    { id: 7, isHeading: false, description: "Blah 5" },
    { id: 8, isHeading: false, description: "Blah 6" },
    { id: 9, isHeading: true, description: "A heading" },
    { id: 10, isHeading: false, description: "Blah 7" },
    { id: 11, isHeading: false, description: "Blah 8" },
    { id: 12, isHeading: false, description: "Blah 9" },
    { id: 13, isHeading: true, description: "A heading" },
    { id: 14, isHeading: false, description: "Blah 10" },
    { id: 15, isHeading: false, description: "Blah 11" },
    { id: 16, isHeading: true, description: "A heading" },
    { id: 17, isHeading: false, description: "Blah 12" },
    { id: 18, isHeading: false, description: "Blah 13" },
    { id: 19, isHeading: false, description: "Blah 14" }
  ]
  function getLines (headingId) {
    var r = []
    var inThere = false
    for (let line of data) {
      if (line.isHeading) {
        if(line.id === headingId) {
          inThere = true
          continue
        } else if (line.id !== headingId &amp;&amp; inThere) {
          return r
        }
      }
      if (inThere) r.push(line)
    }
    return r
  }
  getLines(9)


Basically, it's taking a chunk of a list; it's a state automaton where the inThere state is set by a matching heading ID, and the routine is done when either there are no more items, or a new heading comes up.

Is there a much better way of writing this?
Review


Your function skips until the heading is found and than takes element until the next heading. Perhaps we could split these methods up to make them reusable. 
Try to avoid var (undesired scope), prefer let or const instead.
Prefer a Tree data structure over flat list for hierarchical data.


Refactored for Reusability

Skip items while a predicate is true.

  function skipWhile(items, predicate) {
    let ok = false;
    return items.filter((value, index, array) =&gt; {
      if (!ok &amp;&amp; !predicate(value)){
        ok = true;
      }
      return ok;
    });
  };


Take items while a predicate is true.

  function takeWhile(items, predicate) {
    let ok = true;
    return items.filter((value, index, array) =&gt; {
      if (ok &amp;&amp; !predicate(value)){
        ok = false;
      }
      return ok;
    });
  };


The OP method:

 function getLines (headingId) {
    let lines = skipWhile(data, v =&gt; v.id != headingId);
    lines.shift(); // we don't want the heading
    lines = takeWhile(lines, v =&gt; !v.isHeading);
    return lines;
  }


And verification:

  console.log(getLines(9).map(x =&gt; x.description))


Yielding:


  (3) [ "Blah 7" , "Blah 8" , "Blah 9" ]


You could also create these methods as prototype extensions on Array or refactor them to become generator functions (with yield syntax). I am sure these methods could get optimized for performance somehow.