Question

I'm currently trying to create a "Child Node" using Javascript by grabbing the users input and selection of their "Heading" where the Child node is going to go under.

function addNavigationNodesChild() {
    var idOfParentNode = $('#selectChildParentNavNode').val();
    var nameOfParentNode = $('#selectChildParentNavNode option:selected').text();
    var clientContextChild = new SP.ClientContext(siteRelURL);

    if (clientContextChild != undefined && clientContextChild != null) {
        var webChild = clientContextChild.get_web();

       var quickLaunchNodeCollectionGet = webChild.get_navigation().get_quickLaunch();
       var quickLaunchNodeCollectionGetData = quickLaunchNodeCollectionGet.get_item(idOfParentNode).get_children();


        for (var c = 0; c < navArrayChild.length; c++) {
            var navObjectChild = navArrayChild[c];
            var navTitleChild = navObjectChild.title;
            var navUrlChild = navObjectChild.url;
            var navIsExternalChild = navObjectChild.isExternal;

            // Set properties for a new navigation node.
            var nnciChild = new SP.NavigationNodeCreationInformation();
            nnciChild.set_title(navTitleChild);
            nnciChild.set_url(navUrlChild);
            nnciChild.set_isExternal(navIsExternalChild);

            // Create node as the last node in the collection.
            nnciChild.set_asLastNode(true);
            quickLaunchNodeCollectionGetData.add(nnciChild);
        }
        clientContextChild.load(quickLaunchNodeCollectionGetData);
        clientContextChild.executeQueryAsync(onQueryNavSucceededChild, onQueryNavFailedChild);
        console.log(quickLaunchNodeCollectionGetData);


    }
}

The error I'm getting with this is: Cannot Read Property "get_children" of undefined. Any help is greatly appreciated.

Reference: idOfParentNode is being pulled from a different script which actually works and pulls the correct id's of all the Headings. I've assigned the script that pulls these id's to populate a drop down that users can select from with values.

Example in my HTML: <option value="5">Five</option> Where 5 is the idOfParentNode - also my Header that I want a child node to go into.

EDIT: I have also tried this, with error.

    function addNavigationNodesChild() {
    var idOfParentNode = $('#selectChildParentNavNode').val();
    var nameOfParentNode = $('#selectChildParentNavNode option:selected').text();
    var clientContextChild = new SP.ClientContext(siteRelURL);

    if (clientContextChild != undefined && clientContextChild != null) {
        var webChild = clientContextChild.get_web();
        var quickLaunchNodeCollection = webChild.get_navigation().getNodeById(idOfParentNode);
        console.log(quickLaunchNodeCollection);

        for (var c = 0; c < navArrayChild.length; c++) {
            var navObjectChild = navArrayChild[c];
            var navTitleChild = navObjectChild.title;
            var navUrlChild = navObjectChild.url;
            var navIsExternalChild = navObjectChild.isExternal;

            // Set properties for a new navigation node.
            var nnciChild = new SP.NavigationNodeCreationInformation();
            nnciChild.set_title(navTitleChild);
            nnciChild.set_url(navUrlChild);
            nnciChild.set_isExternal(navIsExternalChild);

            // Create node as the last node in the collection.
            nnciChild.set_asLastNode(true);
            quickLaunchNodeCollection.get_children.add(nnciChild);
            quickLaunchNodeCollection.update();
        }
        clientContextChild.load(quickLaunchNodeCollection);
        clientContextChild.executeQueryAsync(onQueryNavSucceededChild, onQueryNavFailedChild);
        console.log(quickLaunchNodeCollection);
    }
}

Here, I'm using getNodeById method but I get an error stating webChild.get_navigation(...).getNodeById is not a function

Was it helpful?

Solution

Solved with this solution.

    function addNavigationNodesChild() {
    var idOfParentNode = $('#selectChildParentNavNode').val();
    var nameOfParentNode = $('#selectChildParentNavNode option:selected').text();
    var titleOfNavNodeChild = document.getElementById('addNav1Child').value;
var urlOfNavNodeChild = document.getElementById('addNav2Child').value;
    var clientContextChild = new SP.ClientContext(siteRelURL);

    if (clientContextChild != undefined && clientContextChild != null) {
        var webChild = clientContextChild.get_web();
        var quickLaunchNodeCollection = webChild.get_navigation().get_quickLaunch();
        clientContextChild.load(quickLaunchNodeCollection);
        clientContextChild.executeQueryAsync(function () {

        var e = quickLaunchNodeCollection.getEnumerator();
        var notFound = true;
            while (notFound && e.moveNext()) {
            var parentNode = e.get_current();
            if (parentNode.get_title() === nameOfParentNode) {
            var childrenNode = parentNode.get_children();
            notFound = false;
            console.log("found it ")
            var nnciChild = new SP.NavigationNodeCreationInformation();
            nnciChild.set_title(titleOfNavNodeChild);
            nnciChild.set_url(urlOfNavNodeChild);
            nnciChild.set_isExternal(true);

            // Create node as the last node in the collection.
            nnciChild.set_asLastNode(true);
            childrenNode.add(nnciChild);
            clientContextChild.executeQueryAsync(onQueryNavSucceededChild, onQueryNavFailedChild);
            }
        }
    });
  }
}

OTHER TIPS

Here is a more modern example (change get_topNavigationBar for get_quickLaunch as needed) using typescript and async/await:

  async addNavigationNode(title, url, parentTitle, external = true) {
    // Helper fn to wrap JSOM call into awaitable promise
    const executeQuery = async (context: SP.ClientContext) =>
      new Promise((resolve, reject) => context.executeQueryAsync(resolve, reject));
    // Get ctx, web and top navigation items
    const ctx = new SP.ClientContext();
    const web = ctx.get_web();
    const nav = web.get_navigation().get_topNavigationBar();
    // Load and execute so we can iterate the collection
    ctx.load(nav);
    await executeQuery(ctx);

    // Create the new node
    const newNode = new SP.NavigationNodeCreationInformation();
    newNode.set_title(title);
    newNode.set_url(url);
    newNode.set_isExternal(external);
    newNode.set_asLastNode(true);
    // Figure out where to put it: under a parent if specified, otherwise just add to the collection
    let parentNode: SP.NavigationNode = null;
    if (parentTitle) {
      // Look for the parent. Iterate through the top-level items
      const e = nav.getEnumerator();
      while (e.moveNext()) {
        const node = e.get_current();
        // Found it, set the parent node and stop iterating
        if (node.get_title() === parentTitle) {
          parentNode = node;
          break;
        }
      }
      // Add the new node as a child of the parent we just found
      if (parentNode) {
        const children = parentNode.get_children();
        children.add(newNode);
        ctx.load(children);
      }
    } else {
      // No parent: add the new node as a child of the top-level collection
      nav.add(newNode);
    }
    // Execute again to perform the operation
    ctx.load(nav);
    return await executeQuery(ctx);
  }

I find it easier to just add using this function, then go into the site settings navigation area to re-order items.

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top