Validação Ajax


(Ricbhz) #1

Ola pessoal,

Estou mais uma vez precisando de ajuda. Fiz várias pesquisas, mas realmente não consegui solucionar.

É o seguinte: tenho um formulário onde ao preencher um valor monetário num campo textfield, ele chama uma função no Controller e atualiza outro campo. Estava funcionando perfeitamente via AJAX até eu colocar a extensão do priceformat para mascara de moeda neste campo. Após isso simplesmente não chama mais a função no controller.

Outra coisa: Neste mesmo formulário preciso que ao mudar um dropdown contendo duas opções, ele habilite ou desabilite o proximo campo ao lado dele (textfield), dependendo da escolha feita pelo usuário.

Alguém poderia me ajudar por favor nestas duas questões?

Agradeço desde já.


conditional form rule
(Dyegonr) #2

Cara, provavelmente deve ser algum erro com o javascript do priceformat. É algum plugin do jquery que vc botou no Yii? Posta seus codigos do form e do controller ai.

abraço


(Ricbhz) #3

O price format é um pugin para formatar campos para formato moeda. Baixei deste site http://jquerypriceformat.com.

Abaixo meus codigos:

_form


<div class="form">


<?php $form=$this->beginWidget('bootstrap.widgets.TbActiveForm', array(

	'id'=>'sinistro-form',

	'type'=>'horizontal',

        'htmlOptions'=>array('class'=>'well'),

        'enableAjaxValidation'=>true,

        

)); 

Yii::app()->getClientScript()->registerScriptFile(Yii::app()->baseUrl . '/js/jquery.price_format.1.7.min.js');

Yii::app()->clientScript->registerScript('jquery-priceformat', "

$('input[id*=_participacao], input[id*=_orcamento1], input[id*=_orcamento2], input[id*=_orcamento3], input[id*=_valor_rateio], input[id*=_valor_parcial], input[id*=_valor_restante]').priceFormat({

    prefix: 'R$ ',

    centsSeparator: ',',

    thousandsSeparator: '.',

    clearPrefix: true,

});

");

?>


	<p class="note">Campos com <span class="required">*</span> sao obrigatorios.</p>


	<?php echo $form->errorSummary($model); ?>


	<div class="row">

		<?php echo $form->labelEx($model,'participacao'); ?>

		<?php echo $form->textField($model,'participacao',array(

                                'size'=>14,

                                'maxlength'=>14, 

                                'class'=>'span2', 

                                'ajax'=>array(

                                    'type'=>'POST',

                                    'dataType' => 'json',

                                    'url' => Yii::app()->createUrl('sinistro/rateio'),

                                    'success' => 'function(data){

                                        $("input#sinistro_valor_rateio").val(data.valor_rateio);

                                        $("input#sinistro_valor_parcial").val(data.valor_parcial);

                                        $("input#sinistro_valor_restante").val(data.valor_restante);

                                }',

                                ) 

                    )); ?>

		<?php echo $form->error($model,'participacao'); ?>

	</div>


	<div class="column">

		<?php echo $form->labelEx($model,'orcamento1'); ?>

		<?php echo $form->textField($model,'orcamento1',array(

                                'size'=>10,

                                'maxlength'=>10, 

                                'class'=>'input-small', 

                                'ajax'=>array(

                                    'type'=>'POST',

                                    'dataType' => 'json',

                                    'url' => Yii::app()->createUrl('sinistro/rateio'),

                                    'success' => 'function(data){

                                        $("input#sinistro_valor_rateio").val(data.valor_rateio);

                                        $("input#sinistro_valor_parcial").val(data.valor_parcial);

                                        $("input#sinistro_valor_restante").val(data.valor_restante);

                                }',

                                ) 

                    

                    )); ?>

		<?php echo $form->error($model,'orcamento1'); ?>

	</div>

        

        <div class="column">

		<?php echo $form->labelEx($model,'orcamento2'); ?>

		<?php echo $form->textField($model,'orcamento2',array(

                                'size'=>10,

                                'maxlength'=>10, 

                                'class'=>'input-small', 

                                'ajax'=>array(

                                    'type'=>'POST',

                                    'dataType' => 'json',

                                    'url' => Yii::app()->createUrl('sinistro/rateio'),

                                    'success' => 'function(data){

                                        $("input#sinistro_valor_rateio").val(data.valor_rateio);

                                        $("input#sinistro_valor_parcial").val(data.valor_parcial);

                                        $("input#sinistro_valor_restante").val(data.valor_restante);

                                }',

                                ) 

                    )); ?>

		<?php echo $form->error($model,'orcamento2'); ?>

	</div>

        

        <div class="column">

		<?php echo $form->labelEx($model,'orcamento3'); ?>

		<?php echo $form->textField($model,'orcamento3',array(

                                'size'=>10,

                                'maxlength'=>10, 

                                'class'=>'input-small', 

                                'ajax'=>array(

                                    'type'=>'POST',

                                    'dataType' => 'json',

                                    'url' => Yii::app()->createUrl('sinistro/rateio'),

                                    'success' => 'function(data){

                                        $("input#sinistro_valor_rateio").val(data.valor_rateio);

                                        $("input#sinistro_valor_parcial").val(data.valor_parcial);

                                        $("input#sinistro_valor_restante").val(data.valor_restante);

                                }',

                                ) 

                    )); ?>

		<?php echo $form->error($model,'orcamento3'); ?>

	</div>

        

        <div class="column">

		<?php echo $form->labelEx($model,'tipo_rateio'); ?>

		<?php $tipo_rateio = array('Completo', 'Parcial'); 

                    echo $form->dropDownList($model,'tipo_rateio', $tipo_rateio, array(

                    'empty'=>'Selecione',

                    'class'=>'span2',

                    'ajax'=>array(

                            'type'=>'POST',

                            'url' => Yii::app()->createUrl('sinistro/tiporateio'),

                            'update' =>'#sinistro_valor_parcial',

                        ) 

                    )); ?>

		<?php echo $form->error($model,'tipo_rateio'); ?>

	</div>


	<div class="column">

		<?php echo $form->labelEx($model,'valor_rateio'); ?>

		<?php echo $form->textField($model,'valor_rateio',array('size'=>10,'maxlength'=>10, 'class'=>'span2')); ?>

		<?php echo $form->error($model,'valor_rateio'); ?>

	</div>


	<div class="column">

                <?php echo $form->labelEx($model,'valor_parcial'); ?>

                <?php echo $form->textField($model,'valor_parcial',array(

                                'size'=>10,

                                'maxlength'=>10, 

                                'class'=>'input-small', 

                                'ajax'=>array(

                                    'type'=>'POST',

                                    'dataType' => 'json',

                                    'url' => Yii::app()->createUrl('sinistro/restante'),

                                    'success' => 'function(data){

                                        $("input#sinistro_valor_restante").val(data.valor_restante);

                                }',

                                ) 

                    )); ?>

                <?php echo $form->error($model,'valor_parcial'); ?>

        </div>


	<div class="column">

		<?php echo $form->labelEx($model,'valor_restante'); ?>

		<?php echo $form->textField($model,'valor_restante',array('size'=>10,'maxlength'=>10, 'class'=>'input-small')); ?>

		<?php echo $form->error($model,'valor_restante'); ?>

	</div>


	<?php $this->widget('bootstrap.widgets.TbButton', array(

            'label'=>$model->isNewRecord ? 'Cadastrar' : 'Alterar',

            'type'=>'primary', // null, 'primary', 'info', 'success', 'warning', 'danger' or 'inverse'

            'size'=>'normal', // null, 'large', 'small' or 'mini'

            'buttonType'=>'submit',

        )); ?>


<?php $this->endWidget(); ?>


</div><!-- form -->

Controller


/**

         *Função para atualizar o campo valor de rateio de acordo com o menor orçamento lançado, menos o valor de participação 

         */

        public function actionRateio()

        {

            $rateio = 0;

            $valor_parcial = '';

            $valor_restante = '';

            $valor_rateio = $_POST['sinistro']['valor_rateio'];

            $valores = array($_POST['sinistro']['orcamento1'], $_POST['sinistro']['orcamento2'], $_POST['sinistro']['orcamento3']);

            sort($valores, SORT_NUMERIC);// Ordena os itens do array de forma crescente (menor para o maior menor). SORT_NUMERIC para ter certeza que ele vai ordenar como números

            for($i=0;$i<=2;$i++){

                if($valores[$i] > 0){

                    $rateio = (int)$valores[$i] - (int)$_POST['sinistro']['participacao'];

                    if($valor_rateio != $rateio){

                        $valor_parcial = 0;

                        $valor_restante = 0;

                    } else {

                        $valor_parcial = $_POST['sinistro']['valor_parcial'];

                        $valor_restante = $_POST['sinistro']['valor_restante'];

                    }

                    break;

                }

            }

            echo CJSON::encode(array('valor_rateio'=>$rateio, 'valor_parcial'=>$valor_parcial, 'valor_restante'=>$valor_restante));

        }       

        

        public function actionRestante()

        {

            $restante = (int)$_POST['sinistro']['valor_rateio'] - (int)$_POST['sinistro']['valor_parcial'];            

            echo CJSON::encode(array('valor_restante'=>$restante));

        }       

Lembrando que o objetivo é ao entrar com valor de participação ele automaticamente calcula os campos abaixo. Isso funciona do jeito que está atualmente, mas se eu tirar a mascara do price format. Com ela ativa a mascara mas para de atualizar os campos.

A outra coisa é ao escolher o dropdown tipo_rateio na opção Completo ele precisa desabilitar o campo valor_parcial.

Valeu pela ajuda!!


(Dyegonr) #4

Tenta ver se o firebug pega algum erro na execução do ajax. Eu também sugiro vc colocar essa parte do código dentro do controller, em vez de usar na view.


Yii::app()->getClientScript()->registerScriptFile(Yii::app()->baseUrl . '/js/jquery.price_format.1.7.min.js');

Yii::app()->clientScript->registerScript('jquery-priceformat', "

$('input[id*=_participacao], input[id*=_orcamento1], input[id*=_orcamento2], input[id*=_orcamento3], input[id*=_valor_rateio], input[id*=_valor_parcial], input[id*=_valor_restante]').priceFormat({

    prefix: 'R$ ',

    centsSeparator: ',',

    thousandsSeparator: '.',

    clearPrefix: true,

});

");


(Ricbhz) #5

Dyego,

Coloquei o codigo dentro do Controller como sugerido.

Com relação ao firebug não apresenta erro nenhum. Veja na imagem.


(Dyegonr) #6

Pela imagem, oq eu consegui ver é que ele tá sim chamando a função do controller, nao?


(Ricbhz) #7

Não, ele simplesmente faz validação do formulário com a função create padrão, mas na verdade ao mudar do campo "participacao" ele deveria chamar a função rateio e isso ele não está fazendo.


(Lukasz Fokin) #8

Recentemente tive o mesmo problema… quando eu usava o widget de price format, algumas funções de javascript paravam de ser executadas.

O que resolveu foi não usar o wiget, e sim usar a biblioteca do jquery manualmente.

E a outra foi registar o script para fazer o post para controller ao invés de fazer ele no input


(Ricbhz) #9

Oi Lukas, obrigado pela resposta. Desculpe, mas sou iniciante no yii ainda, tem como explicar um pouco melhor como você fez para usar manualmente a biblioteca? Tentei aqui mas não deu certo. Tem algum exemplo por favor?


(Lukasz Fokin) #10

aproveitando o exemplo do amigo acima, seria mais ou menos o seguinte:




//chamada da biblioteca do priceformat

Yii::app()->getClientScript()->registerScriptFile(Yii::app()->baseUrl . '/js/jquery.price_format.1.7.min.js');

//registra o script que gerará a máscara no seu input file

Yii::app()->clientScript->registerScript('jquery-priceformat', "

    $('#iddoseuinput').priceFormat({

        prefix: 'R$ ',

        centsSeparator: ',',

        thousandsSeparator: '.',

        clearPrefix: true,

    });


    $('#iddoseuinput').focusout(function(){

        $.post(CController::createUrl('controller/action'),{valor:$(this).val()}, 

            function(response){

                $('#idInputParaAtualizar').val(response);

            }

        );


    });

", CClientScript::POS_READY);



É mais ou menos isso… aí vc consegue adaptar de acordo com sua necessidade.

O importante é não esquecer de registar as bibliotecas de jquery e priceformar.

Se vc usa google chrome como navegador, existe a ferramenta do desenvolvedor que nela vc consegue ver se seu sistema está dando alguma "pau" de javascript.

Atalho para usa-lá: Ctrl+Shift+j ou nome menu Ferramentas->Ferramentas do Desenvolvedor


(Ricbhz) #11

Oi Lukas, tentei adaptar da seguinte maneira:

_form


<?php echo $form->labelEx($model,'participacao'); ?>

        <?php

            //chamada da biblioteca do priceformat

            Yii::app()->getClientScript()->registerScriptFile(Yii::app()->baseUrl . '/js/jquery.price_format.1.7.min.js');

            //registra o script que gerará a máscara no seu input file

            Yii::app()->clientScript->registerScript('jquery-priceformat', "

                $('input[id*=_participacao]').priceFormat({

                    prefix: 'R$ ',

                    centsSeparator: ',',

                    thousandsSeparator: '.',

                    clearPrefix: true,

                });


                $('input[id*=_participacao]').focusout(function(){

                    $.post(CController::createUrl('sinistro/rateio'),{valor:$(this).val()}, 

                        function(response){

                            $('input[id*=_valor_rateio]').val(response);

                        }

                    );


                });

            ", CClientScript::POS_READY);

            echo $form->textField($model,'participacao',array(

                                'size'=>14,

                                'maxlength'=>14, 

                                'class'=>'span2', ));

            ?>

		<?php echo $form->error($model,'participacao'); ?>

mas apresenta o erro a seguir:

3350

firebug5.png


(Dyegonr) #12

vc pode trocar o CController::createUrl por $this->createUrl()

Tenta aí.


(Lukasz Fokin) #13

É só um probleminha de aspas aí…

troca por isso:





$.post('".CController::createUrl('sinistro/rateio')."',{valor:$(this).val()},


(Ricbhz) #14

Otimo Lukas, agora ele esta chamando a action. Mas ainda não resolveu pois como mencionado inicialmente preciso que o controller verifica alguns valores e retorne mais de um valor para atualizar 3 campos ao mesmo tempo. E fazendo desta forma estou conseguindo trazer apenas 1 valor. Tem como utilizar o JSON com o input da forma que você sugeriu e com a biblioteca do jquery manualmente?

Abaixo codigo do controller para ajudar:


public function actionRateio()

        {

            $rateio = 0;

            $valor_parcial = '';

            $valor_restante = '';

            $valor_rateio = $_POST['sinistro']['valor_rateio'];

            $valores = array($_POST['sinistro']['orcamento1'], $_POST['sinistro']['orcamento2'], $_POST['sinistro']['orcamento3']);

            sort($valores, SORT_NUMERIC);// Ordena os itens do array de forma crescente. SORT_NUMERIC para ter certeza que ele vai ordenar como números

            for($i=0;$i<=2;$i++){

                if($valores[$i] > 0){

                    $rateio = (int)$valores[$i] - (int)$_POST['sinistro']['participacao'];

                    if($valor_rateio != $rateio){

                        $valor_parcial = 0;

                        $valor_restante = 0;

                    } else {

                        $valor_parcial = $_POST['sinistro']['valor_parcial'];

                        $valor_restante = $_POST['sinistro']['valor_restante'];

                    }

                    break;

                }

            }

            echo CJSON::encode(array('valor_rateio'=>$rateio, 'valor_parcial'=>$valor_parcial, 'valor_restante'=>$valor_restante));

        }       


(Newerton Araujo) #15

Ricardo,

Posta o array que esta retornando no:


echo CJSON::encode(array('valor_rateio'=>$rateio, 'valor_parcial'=>$valor_parcial, 'valor_restante'=>$valor_restante))

Se os resultados estiver retornando correto, faz uma alteração:

De:


$.post(CController::createUrl('sinistro/rateio'),{valor:$(this).val()}, 

	function(response){

		$('input[id*=_valor_rateio]').val(response);

	}

);

Para:


$.ajax({

	type: 'POST',

	url: '" . Yii::app()->createUrl('sinistro/rateio') . "',

	data: ({valor:$(this).val()}),

	cache: false,

	dataType: 'json',

	success: function(data){

		console.log(data.valor_rateio);

		console.log(data.valor_parcial);

		console.log(data.valor_restante);

	}

});

Verifica pelo firebug se o log estará mostrando os valores do retorno corretamente, caso sim, e só jogar os valores (data.*) no seus respectivos campos.


(Lukasz Fokin) #16

O mais legal do forum é vc tentar ajudar os outros e descobrir uma forma melhor de fazer aquilo que vc tem feito! aheuaheuahea

Boa Newerton, me ajudou também… Trabalhar com json facilita demais essas requisições ajax!


(Ricbhz) #17

Ola Newerton, o problema é que usando conforme Post #3 o JSON retorna os valores corretos, mas sem o uso do plugin priceformat. Quando uso ele, a função para calcular os valores (actionRateio) não é chamada.

Quando adapto de acordo com exemplo do Lukas (post #10) ele atualiza o campo diretamente, mas não consigo pegar os outros valores pois para fazer o calculo dos outros campos eu preciso pegar via POST alguns valores que não ficam disponiveis quando faço desta forma. Espero ter conseguido explicar, ficou um pouco confuso…

Abaixo imagem do resultado quando faço adaptação de acordo com exemplo do Lukas.


(Newerton Araujo) #18

Ricardo,

Se você remover o prefix e o clearPrefix, não resolve o problema?


$('input[id*=_participacao], input[id*=_orcamento1], input[id*=_orcamento2], input[id*=_orcamento3], input[id*=_valor_rateio], input[id*=_valor_parcial], input[id*=_valor_restante]').priceFormat({

    prefix: '',

    thousandsSeparator: ''

});

Se não funciona faz assim:


$(document).on('focusout','#sinistro-form input[id*=_participacao]',function() {


	$.ajax({

			type: 'POST',

			url: '" . Yii::app()->createUrl('sinistro/rateio') . "',

			data: ({valor:$(this).val()}),

			cache: false,

			dataType: 'json',

			success: function(data){

					console.log(data.valor_rateio);

					console.log(data.valor_parcial);

					console.log(data.valor_restante);

			}

	});


});

E não esquece de remover o ‘ajax’ => array() do dropdownlist() do input participacao.


(Ricbhz) #19

Newerton,

Removi o prefix e o clearPrefix e não resolveu. Fiz as alterações sugeridas e também continua com o mesmo erro.

Quando uso sem o price format a seguinte função é chamada e funciona perfeito. Veja o que ela faz:

_Controller


public function actionRateio()

        {

            $rateio = 0;

            $valor_parcial = '';

            $valor_restante = '';

            $valor_rateio = $_POST['sinistro']['valor_rateio'];

            $valores = array($_POST['sinistro']['orcamento1'], $_POST['sinistro']['orcamento2'], $_POST['sinistro']['orcamento3']);

            sort($valores, SORT_NUMERIC);// Ordena os itens do array de forma crescente. SORT_NUMERIC para ter certeza que ele vai ordenar como números

            for($i=0;$i<=2;$i++){

                if($valores[$i] > 0){

                    $rateio = (int)$valores[$i] - (int)$_POST['sinistro']['participacao'];

                    if($valor_rateio != $rateio){

                        $valor_parcial = 0;

                        $valor_restante = 0;

                    } else {

                        $valor_parcial = $_POST['sinistro']['valor_parcial'];

                        $valor_restante = $_POST['sinistro']['valor_restante'];

                    }

                    break;

                }

            }

            echo CJSON::encode(array('valor_rateio'=>$rateio, 'valor_parcial'=>$valor_parcial, 'valor_restante'=>$valor_restante));

        }       

Quando fiz da forma que você sugeriu ele chama a função acima, mas não tem como receber os valores via POST. No firebug apresenta o seguinte erro: "<h1>PHP Error [8]</h1>

<p>Undefined index: sinistro (C:\wamp\www\associacao_yii\protected\controllers\SinistroController.php:238)</p>".

Nesta linha 238 tem exatamente a o seguinte:


$valor_rateio = $_POST['sinistro']['valor_rateio'];

Ou seja, quando uso da forma que você sugeriu ele retorna apenas o valor que eu digitei na participação e nada no JSON, entendeu?


(Newerton Araujo) #20

Ricardo,

Esse erro e do PHP, é um Warning dizendo que está váriavel não existe.

Olha para o código javascript, você envia a variável ‘valor’:


data: ({valor:$(this).val()}),

Então o correto para resgatar esse valor é $_POST[‘valor’], ou você está enviando outros parâmetros de dados?

Posta o texto da requisição ajax que fica na aba Console, ai você abre a url sinistro/rateio, e veja na aba Postar e mostra o que está sendo enviado.