XF 2.2 How to get the results from a view class?

Orit

Active member
Hello
I'm trying to create a search box for searching for a node from the node list.
I've been using this thread as a guide:

I want to generate a node list in a dropdown menu, similar to the member list dropdown.

I'm having trouble displaying the results in the dropdown- all results are "undefined" so I understand I'm not rendering it correctly.

my code:
My\Addon\Pub\Controller\ForumFind.php (only the relevant function)
PHP:
public function actionAutoComplete()
    {
        $q = ltrim($this->filter('q', 'str', ['no-trim']));

        if ($q !== '' && utf8_strlen($q) >= 2)
        {
            /** @var \XF\Finder\Forum $forums */
            $nodeRepo = $this->repository('XF:Node');
            $forums = $nodeRepo->findNodesForList()
                ->where('node_type_id', 'Forum')
                ->where('title', 'LIKE', '%' . $q . '%')
                ->fetch();
            $viewableForums = [];
            foreach ($forums as $forum) {
                if ($forum->canView()) {
                    $viewableForums[] = $forum;
                }
            }
        }
        else
        {
            $forums = [];
            $viewableForums = [];
            $q = '';
        }

        $results = $forums;

        $viewParams = [
            'q' => $q,
            'forums' => $viewableForums, //$forums,
            'results' => $results
        ];
        return $this->view('Prog\Widgets:Find', '', $viewParams);
    }

My\Addon\Pub\View\Find.php
PHP:
<?php

namespace My\Addon\Pub\View;

use XF\Mvc\View;
use XF\Mvc\Controller;
use XF\Mvc\Router;
use XF\App;

class Find extends View
{
    /**
     * @param string $link
     * @param mixed $data
     * @param array $parameters
     *
     * @return string
     */
    public function buildLink($link, $data = null, array $parameters = [])
    {
        return \XF::app()->router()->buildLink($link, $data, $parameters);
    }
 
    public function renderJson()
    {
        $results = [];
        foreach ($this->params['forums'] AS $forum)
        {
            $results[] = [
                'node_id' => $forum->node_id,
                'title' => $forum->title,
                'url' => $this->buildLink('forums', $forum)
            ];
            $test = $forum;
        }

        return [
            'test' => $this->params['forums'],
            'results' => $results,
            'q' => $this->params['q']
        ];
    }
}

my widget template:
HTML:
<xf:textboxrow name="forums" value="{$forums}" data-xf-init="auto-complete" label="{{ phrase('search_for_a_forum') }}"
               data-single="1" data-acurl="{{ link('forumsearch/auto-complete') }}" />

This is what I get when trying to search:
1717661821355.webp

The number of results is correct, but all results do not contain the title and the link.

What am I doing wrong?

Thanks!!

(I've been using the following link to view the results/errors when there were: http://localhost/hello/index.php?forumsearch/auto-complete&q=for&_xfRequestUri=/hello/index.php?members/admin.1/&_xfWithData=1&_xfToken=1717656091,46fa0ed547cbd68f7c62fbe96c461851&_xfResponseType=json Only I can access it of course. I used it to debugging)

(Please excuse any unnecessary/duplicate code. I have not yet done a cleanup...)
 
Last edited:
What happens if u change

<xf:textboxrow name="forums"

To

<xf:textboxrow name="q"
Thank you!
There is no change...

I had some unnecessary code in the \src\addons\My\Addon\Widget\FindForum.php file.
I've made a few changes to the file and it is now empty just as the \src\XF\Widget\FindMember.php is (I presume the results were called from inside the widget file. The widget file now just calls the widget template).

my route for fetching the results is correct. But now the search box does not show any results.

Can anyone help me understand what am I doing wrong?

Thanks!
 
The default display template for auto-complete results expects icon and text JSON keys, and not title or url. When the value is selected, the input is set and the form is submitted. Then, on the back-end, the input is checked and redirected to the appropriate place. If you want different behavior, you would have to write/extend the JS handlers.
 
I found my mistake (I was printing the various variables for debugging and apparently this was the cause, also the JSON keys were not id/text as I understand they should be).
My current issue:
The items in the dropdown do not redirect to the corresponding forum.
instead I get redirected to /index.php?forumsearch/
and get an error for not having an actionIndex function.

is the index necessary?

corrected files:
PHP:
<?php

namespace My\Addon\Pub\Controller;

use XF\Pub\Controller\AbstractController;
use XF\Repository\Node;

class ForumFind extends AbstractController
{
    

    public function actionAutoComplete()
    {
        $q = ltrim($this->filter('q', 'str', ['no-trim']));

        if ($q !== '' && utf8_strlen($q) >= 2)
        {
            $finder = $this->finder('XF:Node');
            $finder->where('node_type_id', 'Forum')
                ->where('title', 'LIKE', '%' . $q . '%');
            
            $forums = $finder->fetch();
        }
        else
        {
            $forums = [];
            $viewableForums = [];
            $q = '';
        }
        
        $viewParams = [
            'q' => $q,
            'forums' => $forums
        ];
        return $this->view('My\Addon:Find', '', $viewParams);
    }
}

PHP:
<?php

namespace My\Addon\Pub\View;

use XF\Mvc\View;

class Find extends View
{
    /**
     * @param string $link
     * @param mixed $data
     * @param array $parameters
     *
     * @return string
     */
    public function buildLink($link, $data = null, array $parameters = [])
    {
        return \XF::app()->router()->buildLink($link, $data, $parameters);
    }
    
    public function renderJson()
    {
        
        $results = [];
        foreach ($this->params['forums'] AS $forum)
        {
            if ($forum->canView()) {
                $results[] = [
                    'id' => $forum->node_id,
                    'text' => $forum->title,
                    'url' => $this->buildLink('forums', $forum)
                ];
            }
        }

        return [
            'results' => $results,
            'q' => $this->params['q']
        ];
    }
}
 
My current issue:
The items in the dropdown do not redirect to the corresponding forum.
instead I get redirected to /index.php?forumsearch/
and get an error for not having an actionIndex function.

is the index necessary?

Yes. It's ultimately just a regular form, being submitted with the selected value:
When the value is selected, the input is set and the form is submitted. Then, on the back-end, the input is checked and redirected to the appropriate place.

You will need to implement an action which handles the corresponding form submission and redirects to the appropriate place, like \XF\Pub\Controller\Member::actionIndex does.
 
The default display template for auto-complete results expects icon and text JSON keys, and not title or url. When the value is selected, the input is set and the form is submitted. Then, on the back-end, the input is checked and redirected to the appropriate place. If you want different behavior, you would have to write/extend the JS handlers.
Thank you!
I figured that out eventually but from looking at a templatemodifications code file (and the member find) I thought I should pass on id too...

I deleted those lines but I'm still getting a invalid_action error: The requested page could not be found. (Code: invalid_action, controller: My\Addon:ForumFind, action: Index)
 
You will need to implement an action which handles the corresponding form submission and redirects to the appropriate place, like \XF\Pub\Controller\Member::actionIndex does.
Thanks.
I have tried adding it before, but for some reason the results returned here:
return [ 'results' => $results, 'q' => $this->params['q'] ];
Are not being passed on to actionIndex ($params seems to be an empty array).

I'll try again...
 
When you select a result, text should inserted into the input. The rest of the mechanics are the same as if the auto-complete JS doodad wasn't there at all. Imagine you entered a complete forum name into the input yourself, and then submitted the form.
 
When you select a result, text should inserted into the input. The rest of the mechanics are the same as if the auto-complete JS doodad wasn't there at all. Imagine you entered a complete forum name into the input yourself, and then submitted the form.
Ok, I understand. Then no parameters get passed on eventually to actionIndex?
How can I identify what forum was chosen?
 
It's a form submission to a URL, the same as any other. You seemed to have named your input forums, so:
PHP:
$name = $this->filter('forums', 'str');
// ...
 
Thank you so much @Jeremy P for your help!
All is working perfectly now.
I tried printing the variables in many places and that was what broke my code...
 
Last edited:
Back
Top Bottom