Angular 5 click event on cloned DOM structure not triggering - javascript

So I have a hidden DOM structure that I will make visible when clicking on a button (to add some input fields). Now I also want to remove those input fields if not necessary anymore. This is my structure that I clone with jQuery:
<ul id="CTcontainer" class='hidden removeContainer'>
<li>
<label>Content Type Name:</label>
<input class="json-input" type="text" name="CT_name">
</li>
<li>
<label>Content Type Group:</label>
<input class="json-input" type="text" name="CT_group">
</li>
<li *ngIf="contentTypeArray.length != '0'">
<label>Inherit from Content Type:</label>
<select class="json-input" name="CT_contentTypeInherit">
<option *ngFor="let ct of contentTypeArray">{{ ct.name }}</option>
</select>
</li>
<li>
<button type="button" class="btnSubmit" (click)="removeThisCT($event)">Remove these ContentType input fields</button>
</li>
</ul>
Clicking on the "add" button:
public addNewCT(event: Event) {
$('#ContentTypes').append($('#CTcontainer').clone(true, true).removeAttr('id').removeClass('hidden'));
}
When then clicking on the button it should fire this:
public removeThisCT(event: Event) {
alert('testclick');
console.log('testclick');
// $(this).closest('.removeContainer').remove();
}
But nothing happens, debugging in dev tools also shows I'm not entering the function when clicking the button. It seems like my event isn't cloned with? Looking at jQuery .clone() it said to add (true, true) to clone with dataAndEvents and deep events etc. but seemingly doesn't work?
Is this because it's an angular on click event and not a jquery .on('click',) event?

Angular will compile your whole template into javascript to make it fast loading, easy to compress, able to deliver your app as a single file and so forth. More importantly in your case, adding angular template code on the fly will not work, since you are completely bypassing the angular compiler.
As a rule of thumb; when you're writing jquery to manipulate the DOM, you should really question yourself if this really is what you want, and if there's no Angular way of dong it. For a start, all component included in an ngIf or ngFor will be removed completely from the dom once the ngIf turns false or the ngFor does not contain the same numer of elements no more. Use them, and ditch the jquery.
If you want to include whole sets of logic dynamically, read this specific part of the guide:
https://angular.io/guide/dynamic-component-loader
A little piece of code that might help you:
<ul *ngIf="cts.length > 0">
<ng-template ngFor let-ct [ngForOf]="cts">
<li>
<label>Content Type Name:</label>
<input class="json-input" type="text" name="CT_name">
</li>
<li>
<label>Content Type Group:</label>
<input class="json-input" type="text" name="CT_group">
</li>
<li *ngIf="contentTypeArray.length != '0'">
<label>Inherit from Content Type:</label>
<select class="json-input" name="CT_contentTypeInherit">
<option *ngFor="let ct of contentTypeArray">{{ ct.name }}</option>
</select>
</li>
<li>
<button type="button" class="btnSubmit"
(click)="removeThisCT($event)">Remove these ContentType input fields</button>
</li>
</ng-template>
</ul>
adding a ct (whatever that may mean, don't use abreviations in code)
public addNewCT(event: Event) {
this.cts.push({name: 'new ct'});
}
public removeCT(event: Event) {
this.cts = [...this.cts.filter(ct => ct.name != event.name)];
}

Related

value not binding on choose from list with angular ngDefaultControl

I have list of option and using ngDefaultControl Angular directive but formcontrol value show empty on button click.
I want to bind value to form control on button click without using setValue or patchValue methods.
example:
<h3>input text search dropdown</h3>
<div class="result">
Selected Value:
{{
rootForm.get('category')?.value
? rootForm.get('category')?.value
: 'Please select value'
}}
</div>
<br />
<form [formGroup]="rootForm">
<div class="list-popup">
<ul class="list" [formControlName]="'category'" ngDefaultControl>
<li class="item" *ngFor="let option of listValues" [value]="option">
<button type="button" class="item-option" tabindex="-1">
<span class="item-label">{{ option }}</span>
</button>
</li>
</ul>
</div>
</form>
is it possible to bind value from UI in control for the same on selection? Could you please suggest me workaround.
here is the stackblitz
Thanks in advance.
Angular doesn't know what to do when you put a formControl on a ul. In order to do what you want, you have to create a component (or directive) which implements ControlValueAccessor and move the code related to your form control there.
Implementing ControlValueAccessor means implementing the following three functions: writeValue, registerOnChange, registerOnTouched. In this way, Angular will know what to do with your component.
For example, you can follow this example

Send multiple random radio button values to controller in AngularJS

I have built a cross platform app using Monaca, Onsen UI and AngularJS.
On a page I have a list of items, each with a sub-list of radio buttons created as below in my view.html
<ul class="list">
<li class="list__item" ng-repeat="checkItemDescription in data">
<span class="list__item__line-height"><strong>{{checkItemDescription.checkitemdesc}}</strong></span>
<label class="radio-button" ng-repeat="option in checkItemDescription.options">
<input type="radio"
name="option_question_{{option.fleetcheckitemid}}"
ng-model="option.fleetcheckid">
<div class="radio-button__checkmark"></div>
{{option.checkvaluedesc}}
</label>
</li>
</ul>
The list is built and displayed as I want and the user can click on and of the radio buttons to select them.
When the user selects any of the radio buttons on any of the items, I need to save both the "checkItemDescription" ID as well as the "option.fleetcheckid" to a JSON object. My list of items can be of any length and I need to send each list item as a JSON object to my Database.
How do I send bot the "checkItemDescription" ID as well as the "option.fleetcheckid" when my ng-model only contains the value of "option.fleetcheckid"
If the purpose is to be used one time, you can use ng-hide and pass the variable $scope.InputSet and then ng-change, on the function called set the $scope.InputSet as true and the logic you need.
<ul class="list" ng-hide="inputSet">
<li class="list__item" ng-repeat="checkItemDescription in data">
<span class="list__item__line-height"><strong>{{checkItemDescription.checkitemdesc}}</strong></span>
<label class="radio-button" ng-repeat="option in checkItemDescription.options">
<input type="radio"
name="option_question_{{option.fleetcheckitemid}}"
ng-model="option.fleetcheckid"
ng-change="funcToCall(checkItemDescription.id, option.fleetcheckitemid)">
<div class="radio-button__checkmark"></div>
{{option.checkvaluedesc}}
</label>
</li>
</ul>
Controller
$scope.funcToCall = function(checkItemDescription.id, option.fleetcheckitemid){
$scope.inputSet = true;
//Your logic...
};
If you want to remove just that checkbox you have to pass the option and delete it
$scope.funcToCall = function(checkItemDescription.id, option){
// no need to use ng-hide here
$scope.optionId = option.id;
//remove the option
delete option;
//Your logic...
};
This should work.

How can I generate multiple pairs of a number field and a checkbox? (checkbox disables one number field)

I'm trying to generate multiple pairs of a number form and a checkbox.
Clicking the checkbox disables the number field, The problem is that only the first pair is working. Can someone help me?
here's my code: addHRGrade.blade.php
#extends('layouts.default')
#section('content')
<!-- opening the form -->
{{ Form::open(array('url' => 'students/create', 'method' => 'PUT')) }}
#foreach($students as $stud)
<ul>
<li>
<!-- Printing the students retrieved from the dataabase -->
{{ $stud->LName. " , " .$stud->FName }}
<!-- Making a text field for every students -->
<div ng-app="" >
<input name="grade" id="no_grade" type="checkbox" value="0" ng-model="checked" />
<label>No Grade</label>
<input name="grade" id="num_grade" type="number" value="65" ng-model="number" ng-disabled="checked"/>
</div>
</li>
</ul>
#endforeach
<!-- Save button -->
<p> {{Form::submit('Save')}} </p>
<!-- Closing the form -->
{{ Form::close() }}
#stop
Main issue
You're declaring one ng-app="" per table row. I don't think that's what you want to do. You should wrap everything into a single app. Also, you don't assign anything to ngApp and also ngController so your not able to implement any further logic.
Side issues
When you fixed the main issue, you'll see, that every checkbox and textbox will display the same value, since you assign the same model to each checkbox resp. textbox.
The value="65" won't do anything. You want to display the models data, so the models data (which is undefined at startup). To set the initial value use ng-init="number=65".

JS alert on Magento Custom Option click

I have a radio button custom option with 3 options. On selection of option 2, for example, I wish a simple JS alert() to popup with a message regarding this selection, not on all of them, only one.
The problem I'm finding is that to make it compatible with all products they have JS generated ID's and class names so there's little in the way of a pattern to follow to ensure my code works on all products.
I could do it via just looking for that element and getting the second one with getElementByTag(), however I want a Magento-friendly way to do it as I'm heading towards my certification over the coming months and want to ensure my practices are kept in-line with Magento rather than "working around" it.
Example code (ID's, classes and names generated on the fly by Magento)
<dd class="last">
<ul id="options-54765-list" class="options-list">
<li>
<input type="radio" class="radio validate-one-required-by-name product-custom-option" onclick="opConfig.reloadPrice()" name="options[54765]" id="options_54765_2" value="210674" />
<span class="label"><label for="options_54765_2">Colour Edge </label></span>
<script type="text/javascript">$('options_54765_2').advaiceContainer = 'options-54765-container';$('options_54765_2').callbackFunction = 'validateOptionsCallback';</script>
</li>
<li>
<input type="radio" class="radio validate-one-required-by-name product-custom-option" onclick="opConfig.reloadPrice()" name="options[54765]" id="options_54765_3" value="210673" />
<span class="label"><label for="options_54765_3">Gallery Wrap </label></span>
<script type="text/javascript">$('options_54765_3').advaiceContainer = 'options-54765-container';$('options_54765_3').callbackFunction = 'validateOptionsCallback';</script>
</li>
<li>
<input type="radio" class="radio validate-one-required-by-name product-custom-option" onclick="opConfig.reloadPrice()" name="options[54765]" id="options_54765_4" value="210672" />
<span class="label"><label for="options_54765_4">White Edge </label></span>
<script type="text/javascript">$('options_54765_4').advaiceContainer = 'options-54765-container';$('options_54765_4').callbackFunction = 'validateOptionsCallback';</script>
</li>
</ul>
</dd>
To accomplish this, on that product, in the design tab, add in a custom block, like so:
<reference name="before_body_end">
<block type="your_module/product" name="option.select.js" template="path/to/template.phtml" />
</reference>
In your new block, grab the Mage::registry('current_product');, and call getProductOptions(). Filter it down based on whatever criteria. Now, the best might be, depending on if this needs to be reused much, to add a column to Catalog_Model_Product_Option_Value table in the database, and extend the admin templates so you are checking a box, or using a drop-down, or typing some text to get the confirmation to pop up.
Then, in the protected function _toHtml() {} function, output your JS for the confirmation box.
That is how I would do it.

Is it possible to show a html element already on a page a second time without copying it?

I have a page with a hidden form containing several divs.
<form action="...">
<div>
<input id="menubar_open_article_bid" name="bid" onfocus="this.select();" onkeyup="do_v(); type="text">
<a href="#" onclick="return do_h();">
Beitrag öffnen </a>
</div>
<div>
<input id="menubar_open_article_cid" name="cid" onfocus="this.select();" onkeyup="do_a();" type="text">
<a href="#" onclick="return do_y();">
Container öffnen </a>
</div>
<div>
<input id="menubar_open_article_iid" name="iid" onfocus="this.select();" onkeyup="do_b();" type="text">
<a href="#" onclick="return do_x();">
Inhalt öffnen </a>
</div>
</form>
As a first try i copied one of the divs using jQuery to another form in order to show it there (visible).
That worked great, but now the html element id is there twice.
I do not want to change that id. So a solution where i could only reffer to the div with id "menubar_open_article_iid" to show the html-element would solve my problem. Is that possible? (though i never heard of something like this)
As far as I am aware, this is not possible.
I think the main problem here is that you want one input shown twice, but still being the same input. That is going to be problematic, and it is also bad interface design. The user is likely to be confused by having two separate but different inputs in a form.
I'd recommend you to not do this.
Maybe you can leverage this approach:
I'd use jQuery and jQuery metadata:
http://plugins.jquery.com/project/metadata
In your hidden form, don't specify any id's. Instead, specify what you want the ids to be via class metadata:
<form class="hide form-to-clone">
<div>
<input class="setId {id:'id1'}" />
</div>
<div>
<input class="setId {id:'id2'}" />
</div>
<div>
<input class="setId {id:'id3'}" />
</div>
</form>
In jQuery, clone the hidden form:
var clone = $('.form-to-clone').clone();
Then, loop through the elements in the clone and set the ids:
clone.find('.setId').each(function() {
var $this = $(this);
$this.attr('id', $this.metadata().id);
});
Then, append your cloned form to the page somewhere:
clone.show().appendTo('body');

Categories