Handle unique values in tabular input - php

Hope you all doing fine.
Scenario
I have a junction model resumeSkills that takes the id of resume and the id of skill from different tables and another field "proficiency level" to determine the expertise in that particular skill.
I have multiple instances of this model loaded in my page based on "Add New" button click (which triggers a Jquery AJAX callback which interns, creates a model against given index counter).
Every model instance is validated based on model rules defined so it works fine if I have different values selected for every instance created.
Target
Now, I want to add skills in a way that If I select "php" in any model-instance in my view either I am not able to select "php" in any of newly generated model-instances or I don't see in there respective drop-down/tags.
Problem
Now if I select the same value for multiple instances (above figure), Validation fails against second or later record as I have rule that skills can not be duplicated against a resume.
This is where I need Help from the community.
Here is my controller action method to add new model instance (record) in the view (append the content container)
public function actionAddNewRecord($idresume, $index)
{
$model = new OresumeResumeSkill();
$model->idresume = $idresume;
$model->isDeleted = 0;
$model->isFromDb = 0;
$response = [];
$response['content'] = $this->renderPartial('_partials/_add_new_form', [
'model' => $model, 'i'=>$index
]);
return Json::encode($response);
}
Here is the code to my main partial file:
_edit_file.php
<div class="row">
<!-- container that has form and its operations in it -->
<div class="col-xs-12">
<?php
$form = ActiveForm::begin([
'id' => 'form_edit_resume_skill_multiple',
'options' => [
'enctype' => 'multipart/form-data',
'class' => 'section_form',
],
]);
?>
<div id="add_new_record_container">
<!--
Add new Item related item_container will be placed in here dynamically in parallel
This loaded content is based on _add_new_form partial view
Content is added via AJAX request caused by btn_add_new_record
-->
</div>
<div class="row form_controls">
<div class="col-xs-12 text-right">
<input type="hidden" name="hdnCounter" id="hdnCounter" value="<?php echo count($skills); ?>" />
<?php echo Html::a(T::t('main', 'Add New'), ['/oresume/resume-skill/add-new-record', 'idresume'=>$model_resume->idresume], ['id'=>'btn_add_new_record', 'class'=>'btn btn-primary' ]); ?>
</div>
<div class="col-xs-12 text-right">
<?php echo Html::a(T::t('main', 'Cancel'), ['/oresume/attachment/discard-all-drafts'], ['class'=>'btn btn-default', 'id'=>'btnDiscardChanges', 'data'=>['confirm_message'=>T::t('main', 'Discard Changes?'), ] ]);?>
<?php echo Html::submitButton(T::t('main', 'Save Changes'), ['class' => 'btn btn-success']); ?>
</div>
</div>
<?php $attributes = Json::htmlEncode($form->attributes);?>
<script type="text/javascript">
jQuery(document).ready(function($){
<?php
$options = Json::htmlEncode($form->options);
$attributes = Json::htmlEncode($form->attributes);
?>
$("#<?php echo $form->options['id'];?>").yiiActiveForm(<?php echo $attributes;?>, <?php echo $options;?>);
$(".resume_skills").select2({
tags: true,
multiple: true,
maximumSelectionLength: 1,
language: "<?php echo \Yii::$app->language; ?>",
allowClear: true,
placeholder: {
idskill: "",
placeholder: "<?php echo T::t('main', 'Please select'); ?>"
},
});
var attributes = <?php echo $attributes;?>;
for(var i = 0; i < attributes.length; i++) {
$("#form_edit_resume_skill_multiple").yiiActiveForm('add', attributes[i]);
}
});
</script>
<?php ActiveForm::end(); ?>
</div>
<!-- //container that has form and its operations in it -->
</div>
Here is the code for my sub_partial file (to add a new model instance):
_add_new_form.php
$title = T::t('main', 'Add New Record');
$skills = OresumeSkill::listSkills();
$proficiencyLevels = OresumeResumeSkill::listProficiencyLevels();
$form = ActiveForm::begin();
?>
<div class="col-xs-12 item_container">
<div class="row single_value_row">
<div class="col-xs-6">
<?php echo $form->field($model, "[$i]idskill")->dropDownList($skills, ['style'=>['width'=>'100%'], 'class'=>'resume_skills', 'placeholder'=>T::t('main', 'Please select')]); ?>
</div>
<div class="col-xs-5">
<?php echo $form->field($model, "[$i]level")->dropDownList($proficiencyLevels, ['prompt' => T::t('main', 'Please Select')]); ?>
</div>
<div class="col-xs-1 text-left">
<button class="btn btn-danger pull-right btn_remove_record" id="btnRemoveResumeSkill-<?php echo $i;?>"><?php echo T::t('main', '<i class="fa fa-times"></i>'); ?></button>
<?php echo $form->field($model, "[$i]isDeleted")->hiddenInput(['class'=>'isDeleted_input'])->label(false); ?>
<?php echo $form->field($model, "[$i]isFromDb")->hiddenInput(['class'=>'isFromDb_input'])->label(false); ?>
</div>
</div>
<script type="text/javascript">
jQuery(document).ready(function($){
$("#form_edit_resume_skill_multiple").yiiActiveForm('add', 'OresumeResumeSkill[<?php echo $i; ?>]');
$(".resume_skills").select2({
tags: true,
multiple: true,
maximumSelectionLength: 1,
language: "<?php echo \Yii::$app->language; ?>",
allowClear: true,
placeholder: {
idskill: "",
placeholder: "<?php echo T::t('main', 'Please select'); ?>"
},
});
<?php $attributes = Json::htmlEncode($form->attributes);?>
var attributes = <?php echo $attributes; ?>;
for(var i = 0; i < attributes.length; i++) {
$("#form_edit_resume_skill_multiple").yiiActiveForm('add', attributes[i]);
}
});
</script>
</div>
<?php ActiveForm::end(); ?>
And here is the code for my action that handles the dynamically generated models and save them in db.
Public function actionGetResumeSkills($idresume)
{
$model_resume = OresumeResume::findOne($idresume);
$models = OresumeResumeSkill::getResumeSkills($model_resume->idresume);
$response = [];
$postedArray = \Yii::$app->request->post('OresumeResumeSkill');
// print_r($postedArray);
if( count($postedArray) ) //case: Its a postback and we have some models in it
{
if(count($models) < count($postedArray) )//case: postback has more number of models as compared to in db
{
// Generate empty models array to be filled by loadMultiple() method of model class
// create emoty models and add in models array counter so that
// we've equal number of sent / recieved models for processing
for ($i=count($models); $i< count($postedArray); $i++ )
{
$model = new OresumeResumeSkill();
$model->idresume = $idresume;
$models[] = $model;
}
}
}
if( count($models) == 0) // we need to check if this array has something to process
{
$response['status'] = false;
$response['message'] = T::t('main', 'No records found to process');
}
if(OresumeResumeSkill::loadMultiple($models, \Yii::$app->request->post())) // load multiple models of models array
{
$status = true;
foreach ($models as $model)
{
// Delete models that are flaged to do so
// execute continue statement on deletion
// Validate and save models that are to be saved/updated
$model->idskill = OresumeResumeSkill::getSkill($model->idskill);
$model->level = ($model->level != null)? $model->level : OresumeResumeSkill::LEVEL_BEGINNER;
if( $model->validate() ) // Case: Model data is valid
{
// Save Model in database
$status &= $model->save();
}
else
{
$status = false;
// print_r($model->errors['idskill'][0]);
$response['message'] = T::t("main", "Storing of record \"{$model->idskill0->name}\" got some validation issues\n");
}
}
if($status)
{
$model_resume = OresumeResume::findOne($model->idresume);
$models = OresumeResumeSkill::getResumeSkills($model->idresume);
$response['status'] = true;
$response['content'] = $this->renderPartial('_partials/_edit_form', ['model_resume' => $model_resume, 'skills' => $models]);
$response['counter'] = count($models);
$response['message'] = T::t('main', 'Record(s) updated Successfully');
}
else
{
$response['status'] = false;
// $response['message'] = T::t('main', 'Records could not be updated.\n Something went wrong');
}
}
else // case: page loads for the first time
{
$response['content'] = $this->renderPartial('_partials/_edit_form', ['model_resume'=>$model_resume, 'skills' => $models]);
}
return Json::encode($response);
}
Any Help is Appreciated.
thankx in advance.

I'm reading this on a phone so there are a few parts of your code I'm not sure I totally get and I won't be able to type much. However, from my understanding, you don't want already selected skills to show up in next drop down.
You can have a hidden field to keep the IDs of selected skills (comma separated) and pass that as an argument to the listSkills method. Means your listSkills method will change a bit to accept a parameter.
In your listSkills method you have to use a where clause that says where skill ID NOT IN the list of IDs coming from the hidden field. Means you will be selecting back only the skills that have not been selected before into your array for the drop down.
Sorry I'm on a phone, I can't add code samples.

Related

Get id attribute from button and send by AJAX

$(document).ready(function() {
$(".eliminar").click(function(e) {
e.preventDefault();
var id = $(this).attr('data-id');
//alert(id);
$(this).closest('.holder-cesta').remove();
$.post('./php/carro_compra/eliminar.php', {
Id:id
},function(a) {
if (a=='0') {
location.href="./cesta";
}
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="holder-cesta">
<h4>Product 1</h4>
<button class="eliminar" data-id="1">Delete</button>
</div>
<div class="holder-cesta">
<h4>Product 3</h4>
<button class="eliminar" data-id="3">Delete</button>
</div>
<div class="holder-cesta">
<h4>Product 2</h4>
<button class="eliminar" data-id="2">Delete</button>
</div>
I'm creating the button to remove the added products.
Every product added in the cart, will have a delete button.
So my question is, how can i get the id by clicking the delete button.
I was do something like this:
if (isset($_SESSION['carrito'])) {
//Array con datos carrito.
$data = $_SESSION['carrito'];
$total = 0;
for ($i=0; $i<count($data); $i++) {
<div class="holder-cesta">
<h4><?php echo $data[$i]['Titulo']; ?></h4>
<button class="eliminar" data-id="<?php echo $data[$i]['Id']; ?>"><i class="fa fa-trash-o" aria-hidden="true"></i></button>
</div>
<?php
}
} else {
echo "0 articulos";
} unset($arreglo);
?>
My jQuery script look like this:
$(document).ready(function() {
//Button click function.
$(".eliminar").click(function(e) {
e.preventDefault();
//Get the id attribut.
var id = $(this).attr('data-id');
//alert(id); (The alert work perfect).
//Remove the parent holder.
$(this).closest('.holder-cesta').remove();
//Control AJAX
$.post('http://domain.com/php/carro_compra/eliminar.php', {
Id:id
},function(a) {
if (a=='0') {
location.href="./cesta";
}
});
});
});
But i don´t get the ID in my eliminar.php, if i do something like this, it always ignored:
if ($arreglo[$i]['Id'] != $_POST['Id']) {
}
So $_POST['Id'], get nothing from AJAX. If i put the id manual, it work pretty.
Here i include the eliminar.php
<?php
//Session start
session_start();
//Get shoping cart data.
$arreglo = $_SESSION['carrito'];
//Reset.
$arr[] ='';
for ($i=0; $i<count($arreglo); $i++) {
if ($arreglo[$i]['Id']!= $_POST['Id']) {
$datosnuevos = ['Id' => $arreglo[$i]['Id'], 'Titulo' =>$arreglo[$i]['Titulo'], 'Precio' => $arreglo[$i]['Precio'], 'Icon' => $arreglo[$i]['Icon'], 'Cantidad' => $arreglo[$i]['Cantidad'] ];
$arr[] = $datosnuevos;
}
}
if (isset($arr)) {
$_SESSION['carrito'] = $arr;
$data = $_SESSION['carrito'];
$value_carrito = count($data);
$_SESSION['compras'] = $value_carrito;
echo "<script>window.location.reload();</script>";
} else {
unset($_SESSION['carrito']);
unset($_SESSION['compras']);
echo "0";
}
?>

Yii Ajax Validation in widget not working

I'm using Ajax validation in my widget. here is the code.
Widget function
public function run(){
if(!Yii::app()->user->isGuest){
$this->controller->redirect('/');
}
$model= new LoginForm;
// if it is ajax validation request
if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
if(isset($_POST['LoginForm']))
{
$model->attributes=$_POST['LoginForm'];
// validate user input and redirect to the previous page if valid
// blah blah.......
Widget View:
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'login-form',
'enableAjaxValidation'=> true,
'enableClientValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
),
)); ?>
<div class="row">
<?php echo $form->textField($model,'username',array('placeholder'=>'email','class'=>'form-control')); ?>
<?php echo $form->error($model,'username'); ?>
</div>
<div class="row">
<?php echo $form->passwordField($model,'password',array('placeholder'=>'password','class'=>'form-control')); ?>
<?php echo $form->error($model,'password'); ?>
</div>
<div class="row buttons">
<?php echo CHtml::submitButton('Login', array('class'=>'btn btn-primary btn-block')); ?>
</div>
...
Right now the form is not submitting. After I click login nothing happens.
If I make enableAjaxValidation fale, form works but not AJAX.
If I make enableClientValidation false, form works but still no AJAX.
Any ideas? Thanks.
The thing is you are using a single submit button, instead of an ajax submit button.
For this, you may use, for example, an ajaxSubmitButton widget from Yii Bootstrap (or Yii booster).
So, in the SiteController :
...
$model= new LoginForm;
if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
if(isset($_POST['LoginForm']))
{
$model->unsetAttributes();
$model->attributes=$_POST['LoginForm'];
if($model->validate() && $model->login())
{
$array = array('login' => 'success');
$json = json_encode($array);
echo $json;
Yii::app()->end();
}
else{ //This is the important point
if(Yii::app()->getRequest()->getIsAjaxRequest())
{
$array=$model->getErrors();
$json = json_encode($array);
echo $json; //JSON containing the errors set in /models/LoginForm.php
Yii::app()->end();
}
}
}
...
In your view:
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'login-form',
'enableAjaxValidation'=> true,
'enableClientValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
),
));
?>
<div class="row">
<?php echo $form->textField($model,'username',array('placeholder'=>'email','class'=>'form-control')); ?>
<?php echo $form->error($model,'username'); ?>
</div>
<div class="row">
<?php echo $form->passwordField($model,'password',array('placeholder'=>'password','class'=>'form-control')); ?>
<?php echo $form->error($model,'password'); ?>
</div>
<div class="row" >
<?php
/** THIS IS THE AJAX SUBMIT BUTTON **/
$this->widget('bootstrap.widgets.TbButton', array(
'buttonType' => 'ajaxSubmit',
'label' => 'Login',
'ajaxOptions' => array(
'success' =>
'function(data){
var obj = $.parseJSON(data);
if(obj.login=="success"){
//...
// $(location).attr("href","BASEURL/someController/someAction")
}
else{
if("username" in obj){
$("#LoginForm_username_em_").text(obj.username[0]);
$("#LoginForm_username_em_").show();
$("#LoginForm_username").css({"background":"#FEE","border-color":"#C00"});
}
if("password" in obj){
$("#LoginForm_password_em_").text(obj.password[0]);
$("#LoginForm_password").css({"display":"block"});
$("#LoginForm_password").css({"background":"#FEE","border-color":"#C00"});
}
$("#LoginForm_password_em_").show();
}
}'),
));
?>
</div>
In order to use the ajaxSubmitButton widget of Yii Bootstrap (or Yii Booster), you have to download it from http://yiibooster.clevertech.biz/, extract it in your /protected/extensions folder and include it in /protected/config/main.php :
...
Yii::setPathOfAlias('bootstrap',dirname(__FILE__).'/../extensions/bootstrap'); //booster insead of bootstrap if you download the Yii Booster.
return array(
...
'components'=>array(
...
'bootstrap'=>array(
'class'=>'ext.bootstrap.components.Bootstrap', // assuming you extracted bootstrap under extensions
),
)
)
Yii Booster has many other widgets, for this reason I use it. If you don't want to use Yii booster for the ajax submit button, just use the CHtml::ajaxSubmitButton
Ajax validation needs a bit of care.
Please check response at console for ajax call. In ajax validation the output of ajax call should be pure json. In case of ajax validation from widget may include some html with response of ajax call.
have a look at http://www.yiiframework.com/forum/index.php/topic/12222-ajax-validation-in-widget-does-not-work/ hope it may help you.

i can't get the has-error text field in bootstrap

i've been trying to learn yii recently and so i started to work on an simple form with bootstrap. im using yii 1.1.x version not version 2 so i had to install bootstrap manually and write coding based on it.
anyway coming back to the problem it seems that my has-success class is being called correctly by jquery but it does'nt seem so for the has-error...
can someone help and im grateful for your help
<script>
$(document).ready(function() {
$('#contact_name').on('input', function() {
var input = $(this);
var is_name = input.val();
if (is_name) {
$('#contact_name').removeClass("has-success").addClass('has-error');
} else {
$('#contact_name').removeClass("has-error").addClass('has-success');
}
});
});
</script>
<h1>Example Form Validation</h1>
<br>
<div class="form " id="cla">
<?php $form=$this->beginWidget('CActiveForm',array( 'id' =>'form','htmlOptions'=> array('class'=> 'form-horizontal', 'name' => 'forvalidate', 'id' => 'registration-form' ))); ?>
<?php echo $form->errorSummary($model); ?>
<div class="row">
<div class="form-group col-lg-5" id='contact_name'>
<?php echo $form->label($model,'name',$htmloptions = array('class'=>'control-label ',)); ?>
<div class="controls">
<?php echo $form->textField($model,'name',array('name' =>'name' ,'class'=>'form-control col-xs-5', 'aria-describedby'=>'inputSuccess4Status')); ?>
</div>
</div>
</div>
<?php $this->endWidget(); ?>
</div>
<!-- form -->
Try
$('#contact_name').on('input', function() {
var input = $(this);
var is_name = input.val();
if (!is_name) {
$('#contact_name').parent().removeClass("has-success").addClass('has-error');
} else {
$('#contact_name').parent().removeClass("has-error").addClass('has-success');
}
});
I think "has-error" and "has-success" classes don't apply directly on the input but the div where the inputs are
You have to add these classes. See the highlighted code below:
$(document).ready(function() {
$('#contact_name').on('input', function() {
var is_name = $(this).val();
if (is_name) {
$('#contact_name').removeClass("has-success").addClass('has-error');
// ^^^^^^^^^^^^^^^^^^^^^^^
} else {
$('#contact_name').removeClass("has-error").addClass('has-success');
// ^^^^^^^^^^^^^^^^^^^^^^^^
}
});
});

Get data from dropdownlist and insert the value in dataBase

I am trying to get a value from a drop-down list in order to insert in a table in my dataBase. I am using ajax in order to capture this value and draw a button that will insert the value in my database when the user clicks on it.
This is my code :
Yii::app()->clientScript->registerScript('register_script_name', "
$('#editButton').click(function(){
alert('edit');
return false;
});
", CClientScript::POS_READY);
<div class="row">
<?php echo $form->labelEx($model,'Escolha a opção correta <span class="required">*</span>')?>
<?php echo $form->dropDownList($model, 'Opcoes_idOpcoes',$this->getOpcoesResposta(),
array(
'ajax' => array(
'type' => 'POST',
'url'=>$this->createUrl('perguntaOpcoes/State'),
'data'=>array('Opcoes_idOpcoes'=>'js: $(this).val()'),
'update' => '#data',
)
));
?>
</div>
<div id="data">
</div>
And this is my code in controller:
public function actionState()
{
$data= $_POST['Opcoes_idOpcoes'];
echo CHtml::button("Edit",array('title'=>"Edit",'id'=>"editButton",'onclick'=>'edit()'));
}
Can anyone help me ?

How to assign action for earch button in Yii?

I have a page with Groups of Teams which has delete team button next to it.
When team is not in group it has checkbox and button to add team to group.
I wrote in actionView that will render a list of groups with teams.
actionView in GroupController
public function actionView($id) {
$group = $this->loadModel($id);
$teamlst = Group::getAllTeamOfGroup($id);
$teamnotlst = Group::getAllTeamNotInGroup($id);
// Submit
$preSelectedItems = array();
if (isset($_POST['teamlist'])) {
$preSelectedItems = array();
foreach ($_POST['teamlist'] as $selectedItem) {
$preSelectedItems[] = $selectedItem;
}
}
// $teamNo = CHtml::listData($teamnotlst, 'id', 'name');
//Delete
$this->render('view', array(
'model' => $group,
'teamlst' => $teamlst,
'preSelectedItems'=> $preSelectedItems,
'group_id'=>$id,
'teamnotlst' => $teamnotlst,
));
if(isset($_POST['btndeleteteam'])){
TeamGroup::model()->deleteTeamGroup($team->id, $model->ID);
}
}
in view file
<div class="action">
<input type="submit" name="btnupdateteam" value="Update Team">
</div>
<?php echo CHtml::endForm(); ?>
<div class ="team">
<div class="column1">
<?php foreach ($teamlst as $team): ?>
<div class="row">
<?php
echo $team->name;
?>
<input type="submit" name="btndeleteteam" value="Delete Team">
<?php
if(isset($_POST['btndeleteteam'])){
TeamGroup::model()->deleteTeamGroup($team->id, $model->ID);
}?>
</div>
</div><!-- comment -->
<?php endforeach; ?>
<?php
$preSelectedItems = array();
if (isset($_POST['teamlist'])) {
$preSelectedItems = array();
foreach ($_POST['teamlist'] as $selectedItem) {
$preSelectedItems[] = $selectedItem;
}
}
$teamNo = CHtml::listData($teamnotlst, 'id', 'name');
echo CHtml:: checkBoxList('teamlist', $preSelectedItems, $teamNo);
?>
</div>
<div class ="team available">
</div>
My idea is that when you click delete team button it will delete team from group and I has a method for this
TeamGroup::model()->deleteTeamGroup($team->id, $model->ID);
When team not in group it will has checkbox and update button that will add team to group if checkbox is checked.
Thank for advance!
if i understand right what is your problem then you need to read this doc chapter
http://www.yiiframework.com/doc/guide/1.1/en/basics.controller#action
all your actions i.e. delete or add must reside in controller and not in view
instead of this in view:
if(isset($_POST['btndeleteteam'])){
TeamGroup::model()->deleteTeamGroup($team->id, $model->ID);
}?>
you must add something like this into controller
public function actionDelete($id) {
TeamGroup::model()->deleteTeamGroup($id);
$this->redirect('group/view');
}
and instead of this
<input type="submit" name="btndeleteteam" value="Delete Team">
something like this must be in a view
delete
or you can modify CGridView to suite your needs

Categories