在atk4中,我如何使用ajax更新视图

时间:2011-09-30 06:59:26

标签: php ajax frameworks agile atk4

我目前有一个定义的页面,它在行中显示一些数据。在每一行的末尾,有一个视图,显示从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并使用模型值调用set字段?

其次,如果我以这种方式更改它,那么当使用ajax更改数据库值时,是否更容易使用特定id更新视图,如果是这样,我该怎么做?

第三 - 如果我还想根据客户端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');
   }
}

罗马人的代码示例后更新

在遵循Romans提供的代码示例之后,我现在使用页面代码底部的jquery选择器添加URL调用并执行一些jiggery pokery以从id字段获取任务和状态(不确定仅使用HTML5)使用data-id所以只需设置正常的id并从中提取)。以前drop代码在我自己的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();
   }

然后我可以计算新的点数并用剩下的点更新故事,并通过设置模型值并使用update()更新new_status的任务。

如果我现在移动其中一个可拖动,它可以工作,但会打开一个新窗口,再次显示整个页面并报告

AJAXec响应错误:SyntaxError:语法错误

我认为打开额外窗口是因为错误,但错误与响应具有整个页面的所有html有关。我实际上不希望从ajax调用重新加载,除非状态是特定的。

我还需要做的最后一件事就是只在页面上重新加载一个已更新的特定故事的视图。

我尝试过创建一个数组并在首次加载页面时将短变量添加到它中

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

然后在处理GET时在if块中调用它

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

但失败并出现错误

AJAXec响应错误:SyntaxError:missing;在声明之前 致命错误:在第247行的C:\ wamp \ www \ paperless \ page \ scrumwall.php中的非对象上调用成员函数js()


最终更新

导致最后一个错误是因为我没有使用我希望更新的整个视图的外部div中的id。一旦我改变它,它就不再是空的了。

因此,第一次加载页面时,我将所有视图名称存储在循环中的关联数组中,因为我将它们放在页面上

    $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();
   }

请注意,如果我只想更新页面上的一个视图,我可以通过重新加载来调用该对象,并执行该操作,例如。

$ PL-&GT; JS() - &GT;重新加载() - &GT;执行

但如果我想更新页面上的几个视图,我需要将它们放在一个数组(这里称为js [])然后像这样调用execute - 你也可以在Roman的codepad示例中看到这个例子。

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

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

ATK4解决了问题:)

2 个答案:

答案 0 :(得分:1)

你的结构似乎没问题。如果您在其上使用setModel(),它将具有“pointsleft”和“backlog”字段,那么这些字段将自动填入。

我没看到如何定义setID,但你可以扩展setModel,调用parent然后执行它。

我注意到的另一件事是,在你的模板中,最顶级的div应该有id =''。这为js()默认使用的视图提供了唯一的选择。

您正在寻找的.post功能是univ() - &gt; 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链被发送。所有这些都定义了js的第一个参数,例如js(true),js('click')。在我的代码中,我有js('click'),所以它被发送到浏览器。
  3. 用户执行点击按钮等操作。这会触发ajaxec()函数
  4. ajaxec函数使用您在此处指定的参数对页面执行AJAX请求。
  5. 再次执行PHP,但这次它进入if()分支。创建一个没有参数的js(),并且&gt; execute()将javascript发送到浏览器。
  6. 浏览器接收js()...-&gt; execute()的输出并对其进行评估。在我们的例子中,它包含一些其他元素的reload()。
  7. atk4_loader小部件用于执行重新加载其向服务器发送AJAX请求的页面的其他部分
  8. PHP使用cut_object参数执行。它重新初始化原始页面,但只选择性地呈现一个对象。该对象的输出将发送回前端。
  9. PHP还重新生成#2中的JS链,但仅与该对象相关
  10. 前端的atk4_loader接收代码,替换元素的HTML并重新评估javascript。
  11. 回到#3
  12. 听起来好像很多动作。实际上,每次点击有2个请求,如果您立即重新加载,则可以删除一个。请注意,您还可以将参数传递给reload(),然后可以从“get”获取。我不完全理解触发原始脚本中操作的原因,也许我们可以在http://chat.stackoverflow.com/rooms/2966/agile-toolkit-atk4中找到它?

答案 1 :(得分:1)

好的,为了更清晰的答案,我已经整理了一个样本:

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

这里可能的例子可能更好地回答了这个问题。

在您的情况下,由于您正在使用模型,因此应该更容易进行设置。为了表演,我决定使用2个Listers,但理论上你也可以将每个人和任务视为一个视图。

我在会话中存储关联(通过记忆),你将它们存储在数据库中。