Iniciante com dificuldade em eventos de componentes

Olá. Já uso o Prado faz um bom tempo e até já desenvolvi componentes pra ele. Estou aprendendo o Yii, mas não estou conseguindo saber como faço (se é que é possível) para manipular eventos ocorridos num textbox, dropdownlist no Yii, assim como fazia no Prado. Antes eu criava um TTextBox e adionava um manipulador de evento desta forma:


$TBox->onTextChanged[] = array($Obj,'methodName');

Porém, no Yii, o TextBox não é mais uma classe, e, sim, gerado por um método (CHtml::textField()).

Alguém poderia me esclarecer se esta funcionalidade existe no Yii e como implementá-la, ou, se não existe, como simulá-la? O que quero é poder alterar o conteúdo de minha página de acordo com as ações executadas pelo usuário, tipo: selecionar um país numa lista e, ao selecionar, automaticamente recarregar a página (sem alterar os dados já preenchidos) e atualizar uma outra lista de seleção com os respectivos estados (UFs) daquele país.

Grato.

Bom, existem algumas opções.

No Yii, existem os componentes, que tem suporte a eventos. Você pode cria um componente chamado TextBox, que encapsula toda a lógica necessária para exibir o componente, enviar as requisições, etc. Do jeito que você quiser ;D

Outra maneira seria utilizar o JQuery, que já vem "embutido" no Yii. Utilizando ele, basicamente o que precisa ser feito é configurar as opções da requisição. Você pode ver um exemplo disso nesse tutorial do cookbook:

http://www.yiiframework.com/doc/cookbook/24/

Qualquer dúvida, é só falar.

[quote=“CláudioCMSJ, post:1, topic:38171”]

Muito provavelmente tem, visto que o Yii é praticamente um "filho" do Prado. Seria melhor perguntar no forum principal, para tentar obter uma resposta do Qiang.

Vc faz isso facilmente com as opçÕes de Ajax do Yii. Veja em http://www.yiiframework.com/doc/cookbook/24/.

Agradeço às pessoas que responderam. Já estou estudando a solução proposta.

Tentei implementar o exemplo do http://www.yiiframew…c/cookbook/24/ mas confesso que não consegui fazê-lo funcionar. Minha tentativa é com um caso clássico: No meu cadastro de Pessoa devo exibir um dropdownlist que seleciona Estado e abre em outro as Cidades relacionadas ao estado selecionado. Listo meus estados no primeiro dropdown colocando no _form de Pessoa o seguinte código:




          <?php echo CHtml::activeDropDownList(

                estado::model(),

                'id',

                CHtml::listData(estado::model()->findAll(), 'id', 'nome'), 

              // lá no cookbook está echo CHtml::dropDownList('country_id','',    

                            //array(1=>'USA',2=>'France',3=>'Japan'),


                array( 

                    'ajax' => array(

                    'type'=>'POST', //request type

                    'url'=>'dynamiccities', //url to call

                    'update'=>'#cidade_id', //selector to update

                    //'data'=>'js:javascript statement'

                    //leave out the data key to pass all form values through

                )));

        

        //empty since it will be filled by the other dropdown

        echo CHtml::dropDownList('cidade_id','', array());  

        // lá no cookbook echo CHtml::dropDownList('city_id','', array());

        ?>



Até aí Ok, meu dropdown lista os estados da minha tabela. Mas quando seleciono o estado, no dropdown de cidade não acontece nada.

Coloquei essa função no PessoaController, que é a do exemplo do cookbook adaptado.




public function actionDynamiccities()

{

    $data=Location::cidade()->findAll('parent_id=:parent_id',

                  array(':parent_id'=>(int) $_POST['estado_id']));

    // no cookbookl: array(':parent_id'=>(int) $_POST['country_id']));




    $data=CHtml::listData($data,'id','nome'); // no cookbok listData($data,'id','name')

    foreach($data as $value=>$nome)  // no cookbok ($data as $value=>$name)

    {

        echo CHtml::tag('option',

                   array('value'=>$value),CHtml::encode($nome),true); // no cookbook  encode($name)

    }

}



Não sei mais onde mexer para que isso funcione.

Alguém pode me dar uma ajuda?

Obrigado.

É preciso sempre muito cuidado ao copiar códigos! Na verdade, sou contra essa prática. O ideal é ver o exemplo, entender como ele funciona e implementar sua própria solucão. ;)

Não testei aqui, mas acredito que o seu erro está aqui:


$data=Location::cidade()->findAll('parent_id=:parent_id',

                  array(':parent_id'=>(int) $_POST['estado_id']));

De onde você tirou esse Location::cidade()? Você tem algum modelo que tenha uma método static chamado cidade? Acho que não =D

No tutorial do cookbook, temos o seguinte:


$data=Location::model()->findAll('parent_id=:parent_id',

                  array(':parent_id'=>(int) $_POST['estado_id']));

Veja o Location::model(). Essa é a forma correta de utilizar o método findAll, do Active Record. Location é o modelo que representa as cidades, que no seu caso vejo que é a classe cidade. Sendo assim, no seu caso ficaria algo como:


Cidade::model()->findAll()

Note também, que o parâmetro ‘parent_id’, passado para o método findAll, indica que devem ser retornadas todas as cidades onde o campo parent_id tenha o id do estado informado. Você também deve alterar esse parâmetro para refletir o formato de sua tabela.

Para entender melhor como funciona o Active Record no Yii veja: http://www.yiiframework.com/doc/guide/database.ar

Ah, uma dica! Procure iniciar o nome de suas classes (e, por consequência, de seus modelos) com letras Maiúsculas. Vi que seu modelo se chama cidade, com letra minúscula. Isso é ruim e diminui a legibilidade do código, pois faz com que fique fácil de confundir uma classe com uma variável ou método.

Caso o nome de suas tabelas estejam em minusculas e seu banco seja case-sensitive, você pode criar a sua classe normalmente, com letras maiúsculas, e sobrescrever o método tableName() para retornar o nome correto da tabela. Por exemplo




class Cidade extends CActiveRecord {

...

    

    public function tableName() {

        return 'cidade';

    }


...

}



Valeu Davi! Obrigado por responder.

Corrigi os código no quanto às observações que você fez, mas o ele não passa pelo método actionDynamiccities() que coloquei no PessoaController.

Eu uso o Firebug e ele mostra o html com o erro do Yii que diz que "pessoa requisitada não existe".

Quanto às classes em minúsculo creio que é poque estou usando postgres.

Vou debugando por aqui. Se tiver mais alguma sugestão, fico grato.

Você deu permissão para essa action no método accessRules?

Se o usuário não tiver o resultado não é retornado corretamente.

Sim, alterei, mas continua não funcionando.

Vou debugar melhor.

Agora estou com netbeans com plugin para php e com o php configurado para funcionar com o debugger do netbeans. Vou parar de buscar meu erro a unha :)

Obrigado,

Leandro.

Pessoal.

Estou realmente me quebrando para fazer o Dependent Dropdown funcionar.

Estive olhando em vários posts e estou vendo que muita gente não está conseguindo também.

Seria ótimo ver um exemplo funcionando.

Quando eu conseguir fazer essa bagaça funcionar, prometo que posto a solução - funcionando - aqui.

Que surra!

lsorgetz,

Se entendi direito, você disse que a requisição para a action dinamiccyties não estava funcionando, certo?

O que verificou com o firebug? Quando você seleciona um estado ele retorna um erro 404?

Fiz alguns testes aqui, e encontrei um provavel motivo para esse erro.

Por padrão, as url no Yii seguem o seguinte formato:


http://example.com.br/index.php?r=controle/action

No tutorial do cookbook, vemos que ele indica que a requisição ajax deve ser enviada para a ação dinamycccities, ou seja, a requisição será enviada para:


http://example.com.br/dinamyccities

Que claramente é uma URL inválida.

Para indicar a url correta nas opções ajax do dropDownList, utilize o seguinte:


'url'=>array('pessoa/dinamyccities'), 

Assim a requisição será enviada corretamente para a action dinamyccities no controller pessoa.

Beleza Davi!

Com a tua ajuda e mais de um colega meu, resolvemos um problema que estava me incomodando.

Como prometi, segue a solução. (o início das minhas classes continuam em minúsculo, mas vou resolver isso).

No _form.php pessoa coloquei o seguinte código:




        <?php echo CHtml::activeDropDownList(

            estado::model(),

            'id',

            CHtml::listData(estado::model()->findAll(), 'id', 'nome'),

            array(

                'prompt'=>'Escolha um estado',

                'ajax' => array(

                'type'=>'POST',

                'url'=>array('pessoa/dynamiccities'),

                'update'=>'#cidades',

        )));


       echo CHtml::dropDownList('cidades','', array());  ?>




Já no PessoaController.php:




   public function actionDynamiccities() {

        $data=cidade::model()->findAll('estado_id=:id', 

            array(':id'=>(int) $_POST['estado']['id']));


        $data=CHtml::listData($data,'id','nome');

        foreach($data as $value=>$nome) {

            echo CHtml::tag('option',

            array('value'=>$value),CHtml::encode($nome),true);

        }

    }




Agora só falta melhorar o código para que ele traga o dropdown do estado selecionado com o estado da cidade.

Valeu!

Só para ficar mais claro:

Todas as chaves primárias das minhas tabelas são ‘id’ e as chaves estrangeiras ‘tabeladachaveestrangeira_id’