Как создать кнопку «читать дальше» с помощью AJAX в модуле?

Я работаю над действительно простым модулем в Drupal 8, чтобы найти вещи. Что он делает (или, вернее, то, что страница, о которой я спрашиваю в этом вопросе, делает), захватывает некоторые данные из нескольких простых статей в стиле статьи и отображает их.

То, что я хотел бы сделать, это показать только первые (например, 5), а затем нажать кнопку «Читать дальше», в которой AJAX отображает следующие 5, удлиняя страницу так, чтобы теперь он показывает 10.

Вот контроллер, который у меня есть на данный момент. Файл routing.yml указывает на MyController::build. Для простоты я точно не понял, как это получается из базы данных, и простая обработка (в частности, image преобразуется из managed_file в базу данных в URL-адрес изображения).

 class MyController extends ControllerBase {

  public function build() {
    $stuff = $this->getStuff();
    return array(
      '#theme' => 'my_theme',
      '#stuff' => $stuff,
      '#attached' => array(
        'library' => array(
          'my_theme/style',
          'my_theme/readmore',
        ),
      ),
    );
  }

  private function getStuff() {
    $stuff = getStuffFromDatabase();
    $result = array();
    foreach($stuff as $key => $item) {
      $tmp = new \stdClass();
      $tmp->id = $item->id;
      $tmp->title = $item->title;
      $tmp->description = $item->description;
      $tmp->image = $item->image;
      $result[] = $tmp;
    }
  }
}

Которая затем отправляется в файл шаблона:

 <section>
  <ul>
    {% for item in stuff %}
      <li>
        <h3><a href="stuff/{{ item.id }}">{{ item.title }}</a></h3>
        {% if item.image is not empty %}
          <a href="stuff/{{ item.id }}">
            <img src="{{ item.image }}" />
          </a>
        {% endif %}
        {% if item.description is not empty %}
          <p>{{ item.description }}</p>
        {% endif %}
      </li>
    {% endfor %}
  </ul>
</section>
<form method="post" action="" onsubmit="readmore()">
  <button name="read-more" type="submit">Read more</button>
</form>

То, что я хочу, - это способ изменить эту настройку, чтобы сначала контроллер отправлял только несколько записей, но когда кнопка нажата, она отправляет следующие несколько, и шаблон отображает новые, а также как старый.

Спасибо


Хорошо, я думаю Возможно, я решил по крайней мере начать эту проблему. Я следил за этот учебник и хочу получить небольшое сообщение, отображаемое внизу, чтобы хотя бы понять, как Ajax работает с Drupal 8. Я добавил

<div id="current-msg">
  <h2></h2>
  <p></p>
</div>

в нижней части файла .html.twig.

Я создал файл, идентичный его ReadMessageCommand.php, за исключением имени my MyMessageCommand.php (и соответственно переименовал класс внутри него). Функция render имеет myMessage вместо readMessage.

Я добавил метод под названием myMessageCallback в MyController, который работает так же, как в этом руководстве, но с помощью my_module_load_message и MyMessageCommand в соответствующих местах.

В readmore.js, я добавил функцию из приведенного выше руководства, но с помощью readMessage заменено на myMessage. Я также добавил следующее, так что я могу узнать более легко, если функция хотя бы называется.

console.log(response.subject);
console.log(response.content);

И я добавил ссылку core/drupal.ajax в библиотеку readmore.

Мой вопрос в том, как я могу заставить эту функцию вызываться. Насколько я могу судить, руководство, которое я использовал, не имеет никаких указаний на это. Как получить сообщение, которое будет отображаться в div внизу? Как только я это понял, я чувствую, что расширяю его так, чтобы кнопка работала как «прочитанная больше», не должна быть слишком сложной. .

5 голосов | спросил Jim Cullen 28 Jam1000000amThu, 28 Jan 2016 07:07:52 +030016 2016, 07:07:52

2 ответа


0

Этот учебник вам не поможет. Это для более продвинутых вещей.

Я бы не использовал форму, а просто ссылку с ответом ajax.

Но если вы хотите использовать форму, вам нужно создать правильную форму Drupal. Слишком много, чтобы написать здесь, чтобы объяснить, что так просто взгляните сюда https://www.drupal.org/node /2117411

Ваш buildForm должен быть чем-то вроде

 /**
 * {@inheritdoc}
 */
public function buildForm(array $form, FormStateInterface $form_state) {
  // The default value for working with non JS should be taken from the route and adding 1.
  $form['page_number'] = array(
    '#type' => 'hidden',
    '#default_value' => 0,
  );
  $form['my_stuff'] = array(
    '#type' => 'value',
    '#value' => [],
  );
  $form['actions']['#type'] = 'actions';
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => $this->t('Read more'),
    '#button_type' => 'primary',
    '#ajax' => array(
      'callback' => 'Drupal\example\Controller\MyController::myFormSubmit',
    ),
  );
  return $form;
}

Вы можете называть эту форму на своей странице (изменяя соответственно):

$ form = \ Drupal :: formBuilder () -> getForm ('Drupal \ example \ Form \ ExampleForm');

Вы делаете все, что хотите, в своем submitForm, а не в обратном вызове, если хотите, чтобы форма работала без JavaScript. Если вам все равно, что вы можете сделать в обратном вызове ajax. Я предполагаю, что вы делаете это в submitForm.

 /**
 * {@inheritdoc}
 */
public function submitForm(array $form, FormStateInterface $form_state) {
  $page = $form_state->getValue('page_number');
  $stuff = getStuffFromDatabase($page);
  $result = array();
  foreach($stuff as $key => $item) {
    $tmp = new \stdClass();
    $tmp->id = $item->id;
    $tmp->title = $item->title;
    $tmp->description = $item->description;
    $tmp->image = $item->image;
    $result[] = $tmp;
  }
  $page++;
  // Here for non JS you probably would just redirect to the proper page
  $form_state->setValue('page_number', $page);
  $form_state->setValue('my_stuff', $result);
}

Затем в вашем MyController :: myFormSubmit

 use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\AfterCommand;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\InvokeCommand;

public static function myFormSubmit(array $form, FormStateInterface $form_state) {
  $response = new AjaxResponse();
  $selector = $form_state->getValue('my_stuff');

  // Here you build the render array based on the output you want on the page
  $build = [
    '#prefix' => '<div>',
    '#suffix' => '</div>',
  ];
  // The selector is as if you did this in jQuery
  $response->addCommand(new AfterCommand(
    '.some-selector',
    $build
  ));
  $response->addCommand(new HtmlCommand(
    '.some-selector-that-wraps-the-form',
    $form
  ));
  return $response;
}

Вот в чем суть этого. Он должен поставить вас на правильный путь.

Если вы хотите использовать простую ссылку. Вам нужна ваша начальная функция, чтобы принять это во внимание и отправить то, что у вас есть сейчас для не JS, и ответ, как в обратном вызове ajax submit, когда он вызывается через JS.

Обратите внимание, что если вы добавите класс «use-ajax» в ссылку и напишите ссылку «/some /path /nojs», Drapal.Ajax изменит это на «/some /path /ajax», поэтому его легко знаете, вызвано ли вызванное через Ajax или нет.

ответил tic2000 28 Jpm1000000pmThu, 28 Jan 2016 17:51:49 +030016 2016, 17:51:49
0

Я добавил ссылку в блок просмотра в нижнем колонтитуле для отметки всего содержимого, я хочу только выполнить действие при нажатии этой ссылки:

<a id='target-element' href="nojs/ignore_all" class="use-ajax btn btn-default">Ignore all</a>

Вот файл маршрута:

digicare.ignore_all_ajax:
  path: '/nojs/ignore_all'
  defaults:
    _controller: '\Drupal\digicare\Controller\DigicareController::ignore_all'
    _title: 'ignore_all'
  requirements:
    _permission: 'access content'

И контроллер:

namespace Drupal\digicare\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Url;
use Drupal\Core\Link;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
/**
 * Provides route responses for the Example module.
 */
class DigicareController extends ControllerBase {
  /**
   * Returns a ajax callback.
   *
   * @return array
   *   A simple response.
   */
    public function ignore_all() {
       $response = new AjaxResponse();
       $user = \Drupal::currentUser();
       $uid = \Drupal::currentUser()->id();
       $result = views_get_view_result('recent_activity', 'rest_export_1');
       foreach($result as $value){
     if($value->nid){
        // Get a node storage object.
         $entity = \Drupal::entityTypeManager()->getStorage('node');
         // Load a single node.
         $entity = $entity->load($value->nid);  
         $flag_id = 'ignore';
         $flag_service = \Drupal::service('flag');
         $flag = $flag_service->getFlagById($flag_id);
         if (!$flag->isFlagged($entity, $user)) {
        // Unflag the entity for user $account.
         $flag_service->flag($flag, $entity);
         }
      }
       }
        return $response->addCommand(new ReplaceCommand('#target-element', 'Ignore All'));
    } 
}
ответил nehapandya 24 FebruaryEurope/MoscowbFri, 24 Feb 2017 11:52:16 +0300000000amFri, 24 Feb 2017 11:52:16 +030017 2017, 11:52:16

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132