В ATK4, как я могу использовать AJAX для обновления представления

В настоящее время у меня есть определенная страница, которая отображает некоторые данные в строках. В конце каждой строки есть представление, которое показывает общее количество, извлеченное из mysql.

$r->add('View_PointsLeft', 'pleft', 'pointsleft')
           ->setPoints($row['points_left'])
           ->setBacklog($row['backlog_ref'])
           ->setID($row['id'].'-points-left');

Вид определяется с помощью шаблона, подобного этому

<!-- points left -->
<div  class='target points_left'>
  <div class='sticky green'>
    <div class='story'><?$backlog?></div>
    <div id='<?$name?>' class='big_points big_point_margin'><?$pointsleft?></div>
  </div>
</div>
<!-- end 0000-points-left -->

Данные для заполнения представления выбираются с помощью sql на циклической странице, и код /lib/view/pointsleft.php устанавливает методы, которые передают параметры со страницы и обновляют поля в шаблоне.

class View_PointsLeft extends View_Sticky {
  function init(){
    parent::init();
  }

  function setPoints($points){
    $this->template->set('pointsleft',$points);
    return $this;
  }

  function setBacklog($backlog){
    $this->template->set('backlog',$backlog);
    return $this;
  }

  function defaultTemplate(){
    return array('view/scrumwall/pointsleft');
  }
}

Я хочу обновить базу данных, когда что-то меняется на странице, а также обновить общее представление (чтобы уменьшить счетчик).

Во-первых, мне интересно, если я подошел к этому неправильному пути (если каждое представление должно быть автономным) - если я просто передаю поле id в представление, присоедините соответствующую модель к представлению внутри lib / view / pointsleft.php и вызвать установленные поля, используя значения модели?

Во-вторых, если я изменю его таким образом, то облегчит ли это обновление представления с определенным идентификатором при изменении значения базы данных с помощью ajax, и если да, то как мне это сделать?

В-третьих, если я хочу также инициировать обновление базы данных на основе действия на javascript на стороне клиента, куда бы я поместил этот код, например, в версию моего кода, отличную от atk4, у меня был скрипт с именем $.post("update.php"), который обновит mysql. Где бы я положил такой скрипт в ATK4?

Заранее спасибо.


Обновление после ответа от римлян

Человек, ATK4 качается! - это делает больше, чем я ожидал, и я был занят созданием функций внутри представления, чтобы заполнить каждое имя поля, так что теперь переделал его с помощью addModel,

звонок со страницы выглядит так

 $r->add('View_PointsLeft', 'pleft', 'pointsleft')
               ->loadData($row['id']);

шаблоны / представление выглядит так

<div id='<?$name?>' class='target points_left'>
  <div class='sticky green'>
    <div class='story'><?$backlog_ref?></div>
    <div class='big_points big_point_margin'><?$points_left?></div>
  </div>
</div>

и код lib / view выглядит так

<?php
class View_PointsLeft extends View_Sticky {

   function loadData($id){
  $this->setModel('Story')->loadData($id);
   }

   function init(){
      parent::init();
   }

   function defaultTemplate(){
      return array('view/scrumwall/pointsleft');
   }
}

Обновление после примера кода от римлян

Следуя примеру кода, предоставленному римлянами, я теперь добавляю URL-вызов с помощью селекторов jquery внизу кода моей страницы и выполняю некоторые jiggery pokery, чтобы получить задачу и статус из полей id (не уверен, что используйте только HTML5 stufff с использованием data-id, так что просто установите нормальный идентификатор и извлеките из него). Ранее этот код был в моем собственном сценарии univ.js, но у меня нет доступа к переменным php, поэтому я переместил его на страницу

 $p->js(true)->_selector('.movable')->draggable();
 $p->js(true)->_selector('.target')->droppable(array(
                   'drop'=>$this->js(null,'function(event,ui){'.
                           ' target=$(this).attr("id").split("-");'.
                   ' zone=target[2];'.
                               ' sticky=$(ui.draggable).attr("id").split("-");'.
                               ' task=sticky[1];'.
                               ' switch (zone) {'.
                   ' case "verify": newStatus="V";'.
                   '                break;'.
                   ' case "in":     newStatus="P";'.
                   '                break;'.
                   ' case "to":     newStatus="I";'.
                   '                break;'.
                   ' case "done":   newStatus="D";'.
                               '                break;'.
                               '}
                              $.univ().ajaxec({ 0:"'.$this->api->getDestinationURL().'",'. 
                                  'task: task, status: newStatus }); } ')
    ));

и у меня есть блок if, который выглядит следующим образом на странице. Я добавляю Model_Task и загружаю значения, основанные на параметре GET, чтобы у меня также была дополнительная информация, включая историю, к которой он относится, чтобы я также мог обновлять точки, если статус теперь выполнен.

   if($_GET['task'] && $_GET['status'])
   {
        $new_status=$_GET['status'];
        $task_id=$_GET['task'];
        $t=$p->add('Model_Task')->loadData($task_id);
        $old_status=$t->get('status');
        $task_points=$t->get('points');

        if ($new_status<>$old_status & ($new_status=='D' | $old_status=='D'))
        {
           $s=$p->add('Model_Story')->loadData($t->get('story_id'));
           if ($old_status='D')
           {
             $s->set('points_left',$s->get('points_left')+$task_points);
           } else {
             $s->set('points_left',$s->get('points_left')-$task_points);
           }
           $s->update();

           $story=$t->get('story_id');
        }
    $t->set('status',$new_status);
    $t->update();
   }

Затем я могу рассчитать новое количество точек и обновить историю с оставленными точками и обновить задачу с помощью new_status, установив значения модели и используя update ().

Если я сейчас переместлю один из перетаскиваемых объектов, он будет работать, но откроется новое окно, в котором снова будет показана вся страница

Ошибка в ответе AJAXec: SyntaxError: синтаксическая ошибка

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

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

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

 $this->pl_arr[$row['id']]=$r->add('View_PointsLeft', 'pleft', 'pointsleft')
                         ->loadData($row['id']);

а затем в блоке if при обработке GET, чтобы вызвать его

       $pleft=$this->pl_arr[$story];
       $pleft->js()->reload()->execute();

но не получается с ошибкой

Ошибка в ответе AJAXec: SyntaxError: отсутствует; before оператор Fatal error: вызов функции-члена js () для необъекта в C: \ wamp \ www \ paperless \ page \ scrumwall.php в строке 247


Окончательное обновление

Последняя ошибка вызвана тем, что я не использовал идентификатор во внешнем div всего представления, которое я хотел обновить. Как только я изменил это, он больше не является нулевым.

Таким образом, при первой загрузке страницы я сохраняю все имена представлений в ассоциативном массиве в цикле, помещая их на страницу

    $st = $p->add('Model_Story');
    $result = $st->getRows();

    foreach ($result as $row) {
    if (is_array($row)) {
         $r=$p->add('View_Scrumwall_StoryRow')
               ->setWorkspace('ws-'.$row['id']);

        ... other code here ...

      $points_left[$row['id']]=$r->add('View_PointsLeft', null, 'pointsleft')
                      ->loadData($row['id']);
    }

а затем иметь блок if GET, как это

   if($_GET['task'] && $_GET['status'])
   {
        $new_status=$_GET['status'];
        $task_id=$_GET['task'];
        $t=$p->add('Model_Task')->loadData($task_id);
        $old_status=$t->get('status');
        $task_points=$t->get('points');

        if ($new_status<>$old_status && ($new_status=='D' || $old_status=='D'))
        {
           $s=$p->add('Model_Story')->loadData($t->get('story_id'));
           if ($new_status=='D')
           {
             $s->set('points_left',$s->get('points_left')-$task_points);
           } else {
             $s->set('points_left',$s->get('points_left')+$task_points);
           }
           $s->update();
           $story=$t->get('story_id');
           //reload the points left sticky note for the story of the task
           $js[]=$points_left[$story]->js()->reload();
        }
        $t->set('status',$new_status);
        $t->update();
        $js[]=$this->js()->reload();
        $this->js(null,$js)->execute();
   }

Обратите внимание, что если я хочу обновить только одно представление на странице, я могу просто вызвать этот объект chaing с перезагрузкой и выполнить, например:

$ Pl-> JS ()-> Reload()-> выполнить

но если я хочу обновить несколько представлений на странице, мне нужно поместить их в массив (здесь он называется js[]), а затем вызвать execute следующим образом - вы также можете увидеть пример этого в примере кодовой панели Романа.

        $js[]=$points_left[$story]->js()->reload();

        $js[]=$this->js()->reload();
        $this->js(null,$js)->execute();

Проблема решена с ATK4:)

2 ответа

Решение

Хорошо, для более чистого ответа, я собрал образец:

http://codepad.agiletoolkit.org/dragaction.html

Вероятно, пример здесь лучше отвечает на вопрос.

В вашем случае, поскольку вы работаете с моделями, это должно быть проще в настройке. Для исполнения я решил использовать 2 Listers, но теоретически вы также можете иметь представление о каждом человеке и задаче.

Я храню ассоциации в сессии (через запоминание), в вашем случае вы бы сохранили их в базе данных.

Ваша структура, кажется, в порядке. Если вы используете setModel() для него, который будет иметь поля "pointsleft" и "backlog", они будут заполнены автоматически.

Я не вижу, как определяется setID, но вы можете расширить setModel, вызвать parent и затем выполнить это тоже.

Еще одна вещь, которую я заметил, заключается в том, что в вашем шаблоне div самого верхнего уровня должен иметь id=''. Это дает вашему представлению уникальный селектор, который js() использует по умолчанию.

Функция.post, которую вы ищете - это univ()->ajaxec(). Он отправляет данные на сервер, получает JavaScript и выполняет его, отсюда и название. Он ведет себя аналогично форме.

$mybutton->js('click')->ajaxec($this->getDestinationURL(null,array('a'=>'b'));

if($_GET['a']){
    // update database
    $r->getElement('plfat')->js()->reload()->execute();
}

Обычно, чтобы сделать ваш код универсальным, вы можете поместить этот код выше в представление, но вместо "a" вам лучше использовать имя объекта, например так. Это устраняет необходимость в отдельном обновлении обработки страницы:

$this->mybutton->js('click')->ajaxec($this->getDestinationURL(null,
     array($this->name=>'reload'));

if($_GET[$this->name]){
    // update database
    $this->js()->reload()->execute();
}

Обновить

Чтобы уточнить последовательность его выполнения:

  1. Страница отображается в HTML и отправляется в ваш браузер.
  2. Вместе со страницей отправляются цепочки Javascript. Все они, которые определяют 1-й аргумент для js, такие как js(true), js('click'). в моем коде у меня есть js ('click'), поэтому он отправляется в браузер.
  3. Пользователь выполняет действие, такое как нажатие на кнопку. Это вызывает функцию ajaxec ()
  4. Функция ajaxec выполняет AJAX-запрос к странице с указанными там аргументами.
  5. PHP снова выполняется, но на этот раз он идет внутрь ветки if(). Js () без аргумента создается и ->execute() отправляет JavaScript в браузер.
  6. браузер получает вывод js()...->execute() и оценивает его. В нашем случае он содержит reload() для какого-то другого элемента.
  7. Виджет atk4_loader используется для перезагрузки другой части страницы, он отправляет AJAX-запрос на сервер.
  8. PHP выполняется с аргументом cut_object. Он повторно инициализирует исходную страницу, но выборочно отображает только один объект. Выход для этого объекта отправляется обратно во внешний интерфейс.
  9. PHP также генерирует JS-цепочки, как в #2, но относится только к этому объекту.
  10. Atk4_loader от Frontend получает код, заменяет HTML элемента и переоценивает javascript.
  11. вернуться к #3

Похоже, много действий. На самом деле это 2 запроса на клик, и вы можете отменить один, если перезагрузите сразу. Обратите внимание, что вы также можете передавать аргументы в reload(), которые затем можно получить из "get". Я не совсем понимаю, что вызывает действие в вашем оригинальном сценарии, возможно, мы можем узнать это по http://chat.stackru.com/rooms/2966/agile-toolkit-atk4?

Другие вопросы по тегам