API call or JS function to get a list of categories and URL's

Solved Technical Support
  • Is there a way to programmatically get a list of categories and their URL's ?

    Thanks

  • In the browser $.get('/api/categories').then(d => console.log(d.categories));

  • @baris Thanks

  • Odd...

    How come this works

    $.get('/api/categories').then(d => console.log(d.categories));
    {state: ƒ, always: ƒ, catch: ƒ, pipe: ƒ, then: ƒ, …}
    VM406:1 (7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]0: {cid: 2, name: 'General Discussion', description: 'A place to talk about whatever you want', icon: 'fa-comment', slug: '2/general-discussion', …}1: {link: '', class: 'col-lg-4 col-md-6 col-xs-12', icon: 'fa-github', description: 'Stay tuned here to hear more about new releases and features of NodeBB!', order: 3, …}2: {cid: 7, name: 'NodeBB Plugins', description: 'Discussion regarding NodeBB Plugin development.', icon: 'fa-wrench', slug: '7/nodebb-plugins', …}3: {link: '', class: 'col-lg-4 col-md-6 col-xs-12', icon: 'fa-paint-brush', description: 'A public listing of community themes created by the NodeBB community.', order: 5, …}4: {cid: 16, name: 'Technical Support', description: 'Need help with installing or configuring NodeBB? Look here.', icon: 'fa-exclamation-triangle', bgColor: '#A1B56C', …}5: {link: '', class: 'col-lg-4 col-md-6 col-xs-12', icon: 'fa-fire', disabled: 0, description: 'Test NodeBB here! Topics and posts will be cleared on a regular basis.', …}6: {cid: 14, name: 'Area51', description: 'Development category', icon: 'fa-bomb', bgColor: '#fff176', …}length: 7[[Prototype]]: Array(0)
    $.get('/api/categories').then(d => console.log(d.categories[5].name));
    {state: ƒ, always: ƒ, catch: ƒ, pipe: ƒ, then: ƒ, …}
    VM482:1 Testing Ground
    

    But this fails

    $(document).ready(function(){
        $.getJSON("api/categories", function(result){
          $.each(result, function(i, field){
            console.log(field[i].name);
          });
        });
    });
    
    Uncaught TypeError: Cannot read properties of undefined (reading 'name')
        at String.<anonymous> ((index):4337:30)
        at Function.each (nodebb.min.js?v=ot2kkbojvoo:64:2883)
        at Object.success ((index):4336:9)
        at I (nodebb.min.js?v=ot2kkbojvoo:64:29412)
        at Object.fireWith [as resolveWith] (nodebb.min.js?v=ot2kkbojvoo:64:30189)
        at Re (nodebb.min.js?v=ot2kkbojvoo:67:5953)
        at XMLHttpRequest.<anonymous> (nodebb.min.js?v=ot2kkbojvoo:67:8430)
    (
    

    Even with field.name instead, I get undefined in the console..

  • Ok, needed to get my head around the structure of the JSON array. This works fine

    $(document).ready(function(){
        $.getJSON( '/api/categories', function(data, status) {
    $.each(data.categories, function (key, value) {
            console.log("Category name =  " + this.name);
            console.log("Category slug =  " + this.slug);
          });
        });
    });
    
    (index):4337 Category name =  Announcements
    (index):4338 Category slug =  1/announcements
    (index):4337 Category name =  Blog
    (index):4338 Category slug =  3/blog
    (index):4337 Category name =  Bugs
    (index):4338 Category slug =  20/bugs
    (index):4337 Category name =  Chitchat
    (index):4338 Category slug =  19/chitchat
    (index):4337 Category name =  Configure
    (index):4338 Category slug =  5/configure
    (index):4337 Category name =  Debate
    (index):4338 Category slug =  28/debate
    (index):4337 Category name =  General
    (index):4338 Category slug =  2/general
    (index):4337 Category name =  Hosting
    (index):4338 Category slug =  18/hosting
    (index):4337 Category name =  Mentoring
    (index):4338 Category slug =  8/mentoring
    (index):4337 Category name =  Operating Systems
    (index):4338 Category slug =  16/operating-systems
    (index):4337 Category name =  Resources
    (index):4338 Category slug =  25/resources
    (index):4337 Category name =  Security
    (index):4338 Category slug =  11/security
    (index):4337 Category name =  Test
    (index):4338 Category slug =  23/test
    (index):4337 Category name =  Tips
    (index):4338 Category slug =  27/tips
    (index):4337 Category name =  WordPress
    (index):4338 Category slug =  17/wordpress
    
  • phenomlabP phenomlab has marked this topic as solved on
  • @baris coming back here with a question - the above code I provided works fine, but of course, this doesn't fetch children. I see them listed in the JSON array returned, but is there a more efficient way of obtaining these without having to query each category being returned in the loop I have ?

  • You will have to get the children from the children property of each category returned.
    $.get('/api/categories').then(d => console.log(d.categories.map(c => c.children)));

  • @baris Yes, I'm doing that, but this is the result

    Category name =  Announcements | URL = 1/announcements | Children = 
    (index):4346 Category name =  Blog | URL = 3/blog | Children = 
    (index):4346 Category name =  Bugs | URL = 20/bugs | Children = 
    (index):4346 Category name =  Chitchat | URL = 19/chitchat | Children = 
    (index):4346 Category name =  Configure | URL = 5/configure | Children = [object Object],[object Object],[object Object],[object Object]
    (index):4346 Category name =  Debate | URL = 28/debate | Children = 
    (index):4346 Category name =  General | URL = 2/general | Children = 
    (index):4346 Category name =  Hosting | URL = 18/hosting | Children = 
    (index):4346 Category name =  Mentoring | URL = 8/mentoring | Children = [object Object],[object Object]
    (index):4346 Category name =  Operating Systems | URL = 16/operating-systems | Children = [object Object],[object Object]
    (index):4346 Category name =  Resources | URL = 25/resources | Children = [object Object]
    (index):4346 Category name =  Security | URL = 11/security | Children = [object Object],[object Object],[object Object]
    (index):4346 Category name =  Test | URL = 23/test | Children = 
    (index):4346 Category name =  Tips | URL = 27/tips | Children = 
    (index):4346 Category name =  WordPress | URL = 17/wordpress | Children = 
    

    [object Object] is clearly an array, but I can't find any decent way of walking it

    $(document).ready(function() {
        //var categorylist = "";
        $.getJSON('/api/categories', function(data, status) {
            $.each(data.categories, function(key, value) {
                console.log("Category name =  " + this.name + " | URL = " + this.slug + " | Children = " + this.children);
                var categorylist = $(" \
                <li><a class='dropdown-item rounded-1' href='/category/" + this.slug + "'>" + this.name + "</a></li> \
            ");
                $("#thecategories").append(categorylist);
            });
        });
    });
    
  • If the data is an associative array, I'd expect to be able to do something like this.children.name or this.children[key] etc...

  • It is an array so you should be able to do this.children.forEach(child => console.log(child));

  • Thanks. I'll need to find a way of getting this referenced as an object so I can call it.

  • @baris said in API call or JS function to get a list of categories and URL's:

    this.children.forEach(child => console.log(child))

    This is odd..

    $(document).ready(function() {
        //var categorylist = "";
        $.getJSON('/api/categories', function(data, status) {
            $.each(data.categories, function(key, value) {
                //console.log("Category name =  " + this.name + " | URL = " + this.slug + " | Children = " + this.children.forEach(child => child));
                var categorylist = $(" \
                <li><a class='dropdown-item rounded-1' href='/category/" + this.slug + "'>" + this.name + "</a></li> \
                    <ul> \
          <li><a class='dropdown-item rounded-1' href='/category/" + this.children.forEach(child => (child.slug)) + "'>" + this.children.forEach(child => (child.name)) + "</a></li> \
        </ul> \
            ");
                $("#thecategories").append(categorylist);
            });
        });
    });
    

    If I use console.log then console.log(child.slug)) works, but the value isn't being collected to build the li items

    Console Log

    6/customisation
    24/guides
    9/networks
    10/performance
    22/labs
    21/learning
    7/linux
    15/windows
    26/development
    12/malware
    3/privacy
    14/vulnerability
    
  • You want to output one li item for each child so you need to move the loop outside. Something like this

    var categorylist = $(" \
    	<li><a class='dropdown-item rounded-1' href='/category/" + this.slug + "'>" + this.name + "</a></li> \
    		<ul>" + 
    		this.children.map(c => `<li><a class='dropdown-item rounded-1' href='/category/" + ${c.slug} + "'>" + ${c.name}) + "</a></li>`) +
    		"</ul>"
    	);
    

    So for each child category in the children array it will create a li element

  • @baris Of course! Yes - thanks for this. Will change as required.

  • @baris sorted - thanks

    $(document).ready(function() {
        //var categorylist = "";
        $.getJSON('/api/categories', function(data, status) {
            $.each(data.categories, function(key, value) {
                //console.log("Category name =  " + this.name + " | URL = " + this.slug + " | Children = " + this.children.forEach(child => child));
    var categorylist = $(" \
    	<li><a class='dropdown-item rounded-1' href='/category/" + this.slug + "'>" + this.name + "</a></li> \
    		<ul>" + 
    		this.children.map(c => `<li><a class='dropdown-item rounded-1' href='/category/${c.slug}'>${c.name}</a></li>`).join(" ") +
    		"</ul>" 
    	);
                $("#thecategories").append(categorylist);
            });
        });
    });
    

    Added join(" "); to strip the commas from the array

  • More complete code, prettified...

    $(document).ready(function() {
        //var categorylist = "";
        $.getJSON('/api/categories', function(data, status) {
            $.each(data.categories, function(key, value) {
                var categorylist = $(" \
    	<li><span class='category-menu'><i class='fal " + this.icon + "'></i><a style='display: inherit;' class='dropdown-item rounded-1' href='/category/" + this.slug + "'>" + this.name + "</a></span></li> \
    		<ul style='list-style: none;'>" +
                    this.children.map(c => `<li><span class='category-menu'><i class='fal ${c.icon}'></i><a class='dropdown-item rounded-1' style='display: inherit;' href='/category/${c.slug}'>${c.name}</a></span></li>`).join(" ") +
                    "</ul><li class='dropdown-divider'></li>"
                );
                $("#thecategories").append(categorylist);
            });
        });
    });
    

    Looks like this

    image.png

  • @baris one thing that puzzles me is that whilst the newly created menu is dynamically built, and displays fine on desktop, it doesn't show on mobile - apart from the one li I added in the navigation pane, which I am using with an id to bind the dynamically built lines.

    Any thoughts ?

    Thanks

  • Since you are using an id it's only selecting one of the elements. Try a more specific selector like:

    $(".sidebar-left #thecategories").append(categorylist);
    $(".bottombar #thecategories").append(categorylist);
    
  • @baris good idea. Thanks. I'll try that.

  • Generally having more than one element with the same id is not advisable and you should use a class instead.


Suggested Topics


  • template.js not executed

    Solved Technical Support
    0 Votes
    15 Posts
    545 Views

    @baris Dam.. there it is, where all those magic strings meet! 😉
    Thank you.

  • How to get all posts !!!

    Unsolved Technical Support
    0 Votes
    4 Posts
    358 Views

    I've just done it recently.

    call /api/topic/pagination/<tid> to get pagination list for each one call /api/topic/<tid>?<qs> merge results and it's done.

    It will be nice to have an option like ?page=all ...

  • Can't get Nginx to work

    Technical Support
    0 Votes
    7 Posts
    764 Views

    @PitaJ said in Can't get Nginx to work:

    @Goldrush12 said in Can't get Nginx to work:

    I just tried that without success (yes, I made sure to restart NodeBB). Also, the developer mode doesn't fix the problem (contrary to what's stated in the linked thread).

    Okay, so it must be something else.

    I'm not sure if this has anything to do with the issue, but I had a few errors while setting up NodeBB initially, which I had to address.

    Wow, um, big red flag there. How did you install NodeBB in the first place? It may be wise to start from scratch and reinstall with correct permissions from the get-go. You absolutely should not use sudo to install or run NodeBB. The only installation-related things you need root access for are nginx configuration and maybe changing directory privileges before installing NodeBB.

    What OS are you installing NodeBB on? Are you following any tutorials or instructions?

    My OS is Ubuntu 18.04 and I followed a documentation from your website. I started from scratch and it's running fine now! I assume the guide I used must have been outdated, which led to some errors. I must say that it might make sense to clean up the documentary and make sure that only one version of the installation guide for every OS exists to avoid confusion.

    Thank you for your help! 🙂

  • 0 Votes
    3 Posts
    851 Views

    @pitaj said in Noticing "Active Plugins" That Aren't Actually Installed?:

    That list reflects the activated plugins on your forum, ignoring whether or not they are installed. You can fix it by disabling the plugins via running ./nodebb reset -p [plugin name] for each plugin.

    In the future, make sure you disable the plugins before removing them.

    Excellent. Thank you!

  • 0 Votes
    10 Posts
    3k Views

    @pichalite said in How to delete all topics from a Category ?:

    delete/purging topics from the client side does not remove the category

    You are right....so I am left with a 'fake' category which I disable anyway