bug^君 2015-09-23 18:05 采纳率: 25%
浏览 16

ZF2-使用Ajax填充选择

I have my in ProductsForm.php:


    namespace Products\Form;

    use Zend\Form\Form;
    use Zend\Db\Adapter\AdapterInterface;
    use Zend\Db\TableGateway\TableGateway;
    use Zend\Db\Sql\Select;

    class ProductsForm extends Form {

        public function __construct(AdapterInterface $dbAdapter) {

            $this->adapter = $dbAdapter;

            parent::__construct('products');

            $this->add(array(
                'name' => 'state',
                'type' => 'select',
                'attributes' => array(
                    'class' => 'form-control',
                ),
                'options' => array(
                    'empty_option' => 'Select...',
                    'value_options' => $this->getStatesForSelect()
                ),
            ));

            $this->add(array(
                'name' => 'city',
                'type' => 'select',
                'attributes' => array(
                    'class' => 'form-control',
                ),
                'options' => array(
                    'empty_option' => 'Select...',
                    'value_options' => $this->getCitiesForSelect()
                ),
            ));

        }

        public function getStatesForSelect() {
            $dbAdapter = $this->adapter;

            $table = new TableGateway('states', $dbAdapter);
            $result = $table->select(function (Select $select) {
                $select->order('name DESC');
            });

            foreach ($result as $res) {
                $selectData[$res['id']] = $res['name'];
            }
            return $selectData;
        }

        public function getCitiesForSelect($state_id) {
            ??? :(
            select from cities where state_id = $state_id ?
        }

    }

I want to execute the getCitiesForSelect() only when the user select the "state"... and then fill it with values from database based on the state.id value

How can I do that?

  • 写回答

1条回答 默认 最新

  • weixin_33713707 2015-09-24 08:30
    关注

    First of all, do not put the methods getStatesForSelect and getCitiesForSelect in your form. Forms are part of the controller layer, every database request belongs in the model layer: http://framework.zend.com/manual/current/en/modules/zend.mvc.intro.html

    Second: If you did this, you can create an action that will return a json with the requested states and call it via ajax. To load everything properly and nice looking, you will have to make some changes to your form as well:

    $this->add(array(
        'name' => 'state',
        'type' => 'select',
        'attributes' => array(
            'class' => 'form-control',
            'id'    => 'select-state',
        ),
        'options' => array(
            'class' => 'state-option',
            'empty_option' => 'Select...',
        ),
    ));
    
    $this->add(array(
        'name' => 'city',
        'type' => 'select',
        'attributes' => array(
            'class' => 'form-control',
            'id'    => 'select-city',
            'style' => 'display:none',
        ),
        'options' => array(
            'empty_option' => 'Select...',
        ),
    ));
    

    I removed the methods getting your options from the database because, as mentioned, this should be the job of your model table. You set those options in the controller as NandaKumar already wrote:

    $states = $modelTable->getStatesForSelect();
    $form->get('state')->setValueOptions($states);
    

    But this will only fill the states, we need something to fill the cities as well! To do so, we will define an ajax action to get those:

    public function stateCitiesAction()
    {
        if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) 
             && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
            $stateId = $this->params()->fromRoute("id");
            // get your cities table
            // getCitiesForSelect() needs to return an array!
            $cities = $citiesTable->getCitiesForSelect();
            return new JsonModel($cities);
        } else {
            // return a 404 if this action is not called via ajax
           $this->getResponse()->setStatusCode(404);
            return NULL;
        }
    }
    

    The if statement is to make sure, this action is only accessible via ajax. If it is not, it will return a 404.

    I just assumed in this example, that the model actions will return the same arrays as your methods in the form did. Although you could argue about which level should transform the database result, the model itself or the controller. But to keep the example simple I did it this way.

    To resolve a JsonModel properly, you need to include the ViewJsonStrategy in your module.config.php. Otherwise you'd get an error because Zend would try to find a view script.

    'view_manager'    => array(
        //...
        'strategies' => array(
            'ViewJsonStrategy',
        ),
    ),
    

    Plus, we need to pass the id as well. A route param is the most common way to do this and we need to include this in our route definition. This code is not a final solution and should only show you, how you could do this in your config:

    'poducts' => array(
        'type'    => 'Segment',
        'options' => array(
            'route'       => '/products/[:controller][/:action][/:id]',
            'constraints' => array(
                'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                'id'         => '[0-9]*',
            ),
            'defaults'    => array(
                '__NAMESPACE__' => 'Application\Controller',
                'controller'    => 'Index',
                'action'        => 'index',
            ),
        ),
    ),
    

    For more information about routing see: http://framework.zend.com/manual/current/en/modules/zend.mvc.routing.html

    Phew, we are almost done! The only thing left is the ajax call filling the city options. I did this via jQuery:

    $(document).ready(function () {
    
        $("#select-state").change(function () {
            var stateId = $(this).val();
            if(stateId !== "") {
                // you might want to change this
                var url = "products/index/state-cities/"+stateId;
                $.getJSON( url, function( data ) {
                    var options = "";
                    $.each(data, function(id, city) {
                        options += "<option value='" + id + "'>" + city + "</option>";
                    });
                    $("#select-city").html(options).fadeIn();
                });
            }
        });
    
    });
    

    Not that I don't know your routing and you probably need to change the url.

    评论

报告相同问题?

悬赏问题

  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类
  • ¥15 微带串馈天线阵列每个阵元宽度计算
  • ¥15 keil的map文件中Image component sizes各项意思
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据