I am using materialize chips in a typical "Publish Post" form where i use the chips for the tags field. All good.
Now, when i do the same in the almost identical "Edit Post" screen there is a difference, i call from the database the tags the post already has and i insert them in the element where the chips are inserted.
I solved already a couple of that idea's problems but when i want to delete a chip clicking the close icon it doesn't work, either if it's a pre-existing tag or it is a newly generated tag.
This behavior doesn't happen if I don't populate the chip's container with pre-existing tag/chips. So I have 2 options:
I keep trying to make the close icon work populating by myself the chip's container or
I use the addChip method, so probably if I let the plugin generate those pre-existing tag/chips all is going to be fixed.
My problem with the second option is I have no idea how could I make that method work in my code.
Option 1
<div id="chips1" class="chips chips-placeholder input-field">
#foreach($tags as $tag)
<div class="chip" data-tag="{{$tag}}" tabindex="0">{{$tag}}
<i class="material-icons close">close</i>
</div>
#endforeach
</div>
Option 2 (without the foreach populating the div)
<div id="chips1" class="chips chips-placeholder input-field">
</div>
and the JS
/* I initialize the chips with a onChipAdd method
and onDelete method to keep the variable updated */
var val = [];
$('#chips1').chips({
placeholder: 'Etiquetas...',
secondaryPlaceholder: '+Etiqueta',
onChipAdd: function () {
val = this.chipsData;
console.log(val);
},
onChipDelete: function() {
val = this.chipsData;
console.log(val);
}
});
/* ***************************************** */
/* Here populate the hidden input that is going to deliver the
data with the pre-existing chips of Option 1 */
var chipsArr = [];
var chipis = $('#chips1 div.chip');
for (let index = 0; index < chipis.length; index++) {
chipsArr.push($(chipis[index]).data('tag'));
}
$('#chips-values').val(JSON.stringify(chipsArr));
/* ***************************************** */
/* Here i push to the array the newly added tags with the val variable */
$('#publishSubmit').on('click', function (e) {
e.preventDefault();
for (let index = 0; index < val.length; index++) {
chipsArr.push(val[index].tag);
}
$('#chips-values').val(JSON.stringify(chipsArr));
console.log($('#chips-values').val());
$('form#postPublish').submit();
});
I know your question is already a while ago, but maybe it will help you nevertheless. I come across the exact same problem and solved it as follows:
I created the chip container as follows:
<div id="chips" class="chips-placeholder"></div>
<div id="chips_inputcontainer"></div>
Then I created hidden inputs foreach existing chip in the database inside of the "chips_inputcontainer".
For example like this:
<div id="chips_inputcontainer">
<?php foreach($chips as $chip): ?>
<input type='hidden' name='chip[previous][<?php echo $chip['id'] ?>]' value='<?php echo $chip['text'] ?>'>
<?php endforeach; ?>
</div>
At the end, I initalized the chip input with the following JavaScript Snipped:
<script>
$('#chips').chips({
placeholder: 'Enter a tag',
secondaryPlaceholder: '+Tag',
onChipAdd: function(e, chip){
$("#chips_inputcontainer").append("<input type='hidden' name='chip[new][]' value='" + chip.innerHTML.substr(0, chip.innerHTML.indexOf("<i")) + "'>");
},
onChipDelete: function(e, chip){
$('#chips_inputcontainer input[value="' + chip.innerHTML.substr(0, chip.innerHTML.indexOf("<i")) + '"]').val('**deleted**');
},
data: [
<?php foreach($chips as $chip): ?>
{tag: '<?php echo $chip['text'] ?>'},
<?php endforeach; ?>
],
});
</script>
This snippet creates every time when a new chip is added a hidden input with the necessary data.
And every time, when a chip is deleted, the value of the hidden input field is set to **deleted**
And so I know:
which tags are new to the database
which ones are existing ones
which id do the existing ones have in the database
which ones are deleted
I hope, this will help you.
Related
I have a tag (show more) that when user clicks it loads the next 10 results onto what is already there.
I looked around to make this seo friendly but all this talks about is ..
how can i make my relevant for seo next page (really showing more instead of next)
Rather than load with ajax, why not just hide everything after the first 10 and have the next tag show the next 10. See following example.
<style>
.hide{
display: none;
}
</style>
<div id='contain'>
<?php
//Not sure what you are loading but this is a dummy loop done in PHP
$i=0;
while($i<101){
//Set the class based on the result. If greater than 10 then hide this result.
$class = ($i<10 ? "result" : "result hide");
echo"<div class='$class'>
<p>MY CONTENT</p>
</div>";
$i++;
}
?>
</div>
<a href='#' id='showMore'>Show 10 More</a>
<script>
$('#showMore').click(function(e){
e.preventDefault();
var i = 0;
$('.hide').each(function(){
if(i<10){
$(this).removeClass('hide');
}
else{
return;
}
i++;
});
});
</script>
That is the only way I can think of solving the problem. I understand ajax is being used to speed up the query.
I am kind of lost on how to do this in my view.
I want to add the quantity. Right now, it adds but how do I get the input value into my ajaxlink?
My controller is using session to add.
<input id="quantity" type="text" value="1" class="span1">
<div id="cart-text">
<?php echo CHtml::ajaxLink(' Add ',
Yii::app()->createUrl('controller/basketAjax',array('id'=>$_GET['id'])),
array('success'=>'function(data){...
controller:
$session=new CHttpSession;
$session->open();
if (!isset(Yii::app()->session['cart']))
{
$quantity = 1;
$session->add('cart',array(
'product_id.'.$id=>array("id"=>$id,
'quantity'=>$quantity)
));
}
else
{
$cart = Yii::app()->session['cart'];
$array = $cart['product_id.'.$id];
if (isset($array)){
$array['quantity']=$array['quantity']+1;
} else {
$t = array('product_id.'.$id=>array("id"=>$id,'quantity'=>$quantity));
array_push($cart,$t);
}
$session->add('cart', $products);
}
you can do this by using keyup function of jquery. First set the id of link as "mylink". Compute the url by using createUrl.
<script type="text/javascript" >
$("#quantity").keyup(function(){
var url=<?php echo Yii::app()->createUrl('controller/basketAjax') ?>;
$("#mylink").attr("href","");
$("mylink").attr("href",url +$(this).val());
});
</script>
Now i explain whats happening above. first i catch the event keyup on input you are using. It will be called each time you press a key on input. Now url=<?php echo Yii::app()->createUrl('controller/basketAjax') ?>; this code is returning you the base url to your action without any parameters being passed.this line $("#mylink").attr("href",""); will set the href of your link to " "( means nothing). Now this line $("mylink").attr("href",url +$(this).val()); is appending the value of the input you are getting from the input.
Remember you have to put the separator in between like
$("mylink").attr("href",url+"/" +"id"+"/"+$(this).val());
Above i have assumed that the href in your case looks like "projectname/index.php/controller/action/id/something". Thats y i have used separators in between but you can customize it according to your needs.
ajaxLink will not work (from what I know), just build it the old fashion way with jquery. Your best solution is actually to put it in a form and submit the form. Something like
<?php
Yii::app()->clientScript->registerCoreScript('yiiactiveform');
$form=$this->beginWidget('CActiveForm', array('action'=>Yii::app()->createUrl('cart/addProduct')));?>
<input type="text" name="quantity" value="1">
<input type="hidden" name="Product_id" value="<?php echo $model->id;?>">
<?php echo CHtml::ajaxSubmitButton('Save',CHtml::normalizeUrl(array('cart/addProduct','render'=>true)),
array(
'dataType'=>'json',
'type'=>'post',
'success'=>'function(data) {
if(data.status=="success"){
$("#formResult").html("form submitted successfully.");
}
else{
$.each(data, function(key, val) {
$("#user-form #"+key+"_em_").text(val);
$("#user-form #"+key+"_em_").show();
});
}
}',
)); ?>
<?php $this->endWidget(); ?><!-- .contact -->
Sorry for the indenting, hard to indent properly here.
I have what I think is a simple scenario where I have to generate multiple textareas with RTE capability. I am using TinyMce which works marvelously if I only have one textarea, but the others don't. I have created a simple example MVC 4 app to try to get it all working before migrating my new knowledge to the real app. There are other items on this page that are all editable so it appears that the problem might stem from the html helper. Or from the fact that the resultant html shows that all three textareas have the same id. However, since the code doesn't obviously reference the id I didn't think I would matter. Anyone know for sure?
I have a simple model:
TextModel text = new TextModel();
text.P1 = "This is an editable element.";
I have included TinyMce in my BundleConfig file, then in my _Layout. Then I have a strongly typed view.
#model TinyMCE_lite.Models.TextModel
And a script section to expand my textareas on focus:
<script>
$(window).load(function () {
$('textarea.expand').focus(function () {
$(this).addClass("expanding")
$(this).animate({
height: "10em"
}, 200);
});
$('textarea.expand').blur(function () {
$(this).animate({
height: "28px"
}, 100);
$(this).removeClass("expanding")
});
});
Then I crank out three in a loop:
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<fieldset>
<h1 class="editable">Editable header</h1>
#for (int count = 0; count < 3; count++ )
{
int index = count + 1;
<h3>#index</h3>
<p class="editable">#Html.DisplayFor(model => model.P1)</p>
#Html.TextAreaFor(model => model.P2, 0,0, new { #class = "expand" })
}
<div style="margin-top: 25px;"><input type="submit" value="Save" /></div>
</fieldset>
}
The first one acts as expected, showing the editor elements, but not the others. All three expand as expect. Hopefully I have overlooked something simple. Any ideas?
Wow! Turns out it was the identical ids. All I had to do was create unique ids and it works nicely.
I changed this:
#Html.TextAreaFor(model => model.P2, 0,0, new { #class = "expand" })
to this:
#Html.TextAreaFor(model => model.P2, 0,0, new { #class = "expand", id = #count })
Hopefully this will prevent someone else from hours of agony trying to figure this out.
By default a dojo.dnd.Source container allows you to hold Ctrl to duplicate/copy a dragged item rather than just move it.
I know you can set singular=true to stop multiple items being dragged but how do I stop copying? Duplicating items makes no sense in the context of my items (I am making a draggable list for reordering pages on a website menu).
Thanks
I'm unsure if there's a nicer way, but I've always accomplished this by clobbering the copyState method on the Source instance to always return false.
If you've got several Sources on the page, you could also elect to dojo.declare a subclass with the method overridden, or dojo.extend dojo.dnd.Source itself to clobber the method in all instances.
Or second option
dojo.addOnLoad(function(){
//Disable the key events Ctrl and Shift
dojo.extend( dojo.dnd.Source, { copyState: function( keyPressed, self ){
return false; }}
);
//Create the dnd source object for data point column bar
columnBar = new dojo.dnd.Source("viewColumnBar",{ singular: true });
});
Thanks to Ken Franquiero, I managed to solve this problem. For others in the same boat, here's my code:
/**
* Extend dojo.dnd.Source to prevent copying
*/
dojo.require( 'dojo.dnd.Source' );
dojo.addOnLoad( function() {
dojo.declare
(
'EditPosition',
dojo.dnd.Source,
{
copyState: function( keyPressed, self )
{
return false;
}
}
);
oEditPosition = new EditPosition
(
'position_container',
{
withHandles: 'true'
}
);
} );
HTML:
<div id="position_container">
<div class="dojoDndItem">
<div class="dojoDndHandle drag_icon drag_handle"></div> <strong>Short Paragraphs</strong>
</div>
<div class="dojoDndItem">
<div class="drag_icon fixed_handle"></div> About Us
</div>
<div class="dojoDndItem">
<div class="drag_icon fixed_handle"></div> Team Members
</div>
</div>
I use Dojo 1.3.1, essentially under FF3.5 for now.
I have a dnd source which is also a target. I programmatically add some nodes inside, by cloning template items. The aim for the user is then to use dnd to order the items. It is ok for one or two actions, then I got the "this.manager.nodes[i] is null" error in Firebug, then no more dnd action is taken into account.
My HTML (jsp), partial:
<div id="templates" style="display:none">
<div class="dojoDndItem action" id="${act.name}Template">
<fieldset>
<legend class="dojoDndHandle" >${act.name}</legend>
<input id="${act.name}.${parm.code}." type="text" style="${parm.style}"
dojoTypeMod="dijit.form.ValidationTextBox"
/><br>
</fieldset></div>
</div>
My Javascript for adding/removing dnd items nodes, partial :
function addActionFromTemplate(/* String */actionToCreate, /* Object */data) {
// value of actionToCreate is template id
var node = dojo.byId(actionToCreate + "Template");
if (node) {
var actNode = node.cloneNode(true);
// make template id unique
actNode.id = dojo.dnd.getUniqueId();
// rename inputs (add the action nb at the end of id)
// and position dojo type (avoid double parsing)
dojo.query("input[type=text], select", actNode).forEach( function(input) {
input.id = input.id + actionsCount;
dojo.attr(input, "name", input.id);
dojo.attr(input, "dojoType", dojo.attr(input, "dojoTypeMod"));
dojo.removeAttr(input, "dojoTypeMod");
});
// insert the action at script's tail
actionList.insertNodes(true, [ actNode ]);
dojo.parser.parse(actNode);
// prepare for next add
actionsCount++;
}
}
function deleteAction(node) {
var cont = getContainerClass(node, "action");
// remove the fieldset action
cont.parentNode.removeChild(cont);
}
Thanks for help ...
OK, it seems that, finally, simply using :
actionList.insertNodes(false, [ actNode ]);
instead of
actionList.insertNodes(true, [ actNode ]);
fixed the pb .