Hello Stackoverflow 커뮤니티!
저는 AngularJS 및 jQuery와 함께 Symfony 3 프로젝트를 진행하고 있습니다. Symfony 양식 빌더와 인터페이스하여 컬렉션 필드 유형에 대한 행을 추가 및 제거하는 콜렉션 지시문을 작성했습니다. 이 지시문은 prototypeControl이라는 양방향 바인딩 변수를 설정하는 격리 된 범위를가집니다. 나뭇 가지 템플릿 사이트에서 prototype-control="{{ form.vars.id|camel_case }}Prototype"
을 호출하면 컬렉션 필드의 고유 ID를 가져와 단일 양식의 여러 컬렉션 필드에서 작동합니다. prototype-control 속성에서 prototypeControl에 변수 이름을 설정하면 모든 것이 잘 동작합니다. 추가 및 삭제 버튼은로드시 존재하는 콜렉션 행에 대해 작동하며 삭제 버튼은 동적으로 추가 된 행에 대해 작동합니다. 사용자 정의 변수 이름을 사용하려면이 작업이 필요하므로 페이지 컨트롤러에서 분리 된 범위 함수로 작업 할 수 있습니다.
간단히 말해 양식 ID로 변수를 사용하여 고유하게 만들면 javscript 콘솔에서 함수를 트리거 할 수 있지만 동적으로 추가되는 필드는 삭제 버튼이 영향을 미치지 않습니다. delete 버튼을 작동시킬 수있는 유일한 방법은 지시문에 $ compile을 삽입하고 directvie 요소를 컴파일하는 것입니다.
$compile(element.contents())(scope);
다른 수준의 DOM에서 컴파일을 시도했지만 삭제 버튼이 작동하지 않습니다. 내가 시도한 예제 요소는 삭제 버튼 자체, 로컬 컨테이너 변수에 저장된 DOM, 프로토 타입 HTML 자체 및 .prototype-row를 시도한 것입니다. 이들 중 어느 것도 $ compile에서 영향을받지 않는 것 같습니다. 요소 변수를 컴파일하는 것만 작동하는 것 같습니다. 여기
($_ => {
$_.app.directive('formCollection', [
'$compile',
($compile) => ({
restrict: 'C',
require: '^form', // Grab the form controller from the parent <form> element,
scope: {
prototypeControl: '=',
},
link(scope, element, attr, form) {
// Declare prototypeControl as an object
scope.prototypeControl = {};
// Store the prototype markup in the scope (the template generated by Symfony)
scope.prototype = attr.collectionPrototype;
// Determine what the the next row id will be on add
let row = element.find('.prototype-row').last().data('row');
// Set the nextRow scope variable
if (typeof row !== 'undefined') {
// Next number in the sequence
scope.nextRow = row + 1;
}
else {
// There are no rows on page load. Setting the default to zero
scope.nextRow = 0;
}
// Add prototype row (add button)
scope.prototypeControl.add = ($event) => {
if (typeof $event !== 'undefined') {
// Prevent Default
$event.preventDefault();
}
// Get the element that will contain dynamically added prototype form rows
let container = element.find('.prototype-container');
// Replace the __name__ placeholder with the row id (typically the next number in the sequence)
let prototype = scope.prototype.replace(/__name__/g, scope.nextRow);
// Appened the prototype form row to the end of the prototype form rows container
angular.element(prototype).appendTo(container);
// Re-compiles the entire directive element and children to allow events like ng-click to fire on
// dynamically added prototype form rows
$compile(element.contents())(scope);
// Increase the nextRow scope variable
scope.nextRow++;
};
// Remove prototype row (remove button)
scope.prototypeControl.remove = ($event) => {
// Prevent Default
$event.preventDefault();
// Get the button element that was clicked
let el = angular.element($event.target);
// Get the entire prototype form row (for removal)
let prototypeRow = el.parents('.prototype-row');
// Remove the row from the dom (If orphan-removal is set to true on the model, the ORM will automatically
// delete the entity from the database)
prototypeRow.remove();
};
// Manual control to add a row (omits the $event var)
scope.prototypeControl.addRow =() => {
scope.prototypeControl.add();
};
// Manual control to remove a row by passing in the row id
scope.prototypeControl.removeRow = (row) => {
// Find the prototype form row by the row id
let el = angular.element(`.prototype-row[data-row="${row}"]`);
// If the element is found, remove it from the DOM
if (el.length) {
el.remove();
}
};
}
})]);
})(Unicorn);
서버 측으로부터 수집 용 나뭇 템플릿 블록이다 : 여기
가 지정된다.{%- block collection_widget -%}
{% if prototype is defined and prototype %}
{% set prototypeVars = {} %}
{% set prototypeHtml = '<div class="prototype-row" data-row="__name__">' %}
{% set prototypeHtml = prototypeHtml ~ form_widget(prototype, prototypeVars) %}
{% if allow_delete is defined and allow_delete %}
{% set prototypeHtml = prototypeHtml ~ '<div class="input-action input-action-delete">' %}
{% set prototypeHtml = prototypeHtml ~ '<a href="#" class="btn btn-secondary btn-destructive btn-small prototype-remove" ng-click="' ~ form.vars.id|camel_case ~ 'Prototype.remove($event)" data-field="' ~ prototype.vars.id|camel_case ~ '">' ~ deleteButtonText|trans({}, translation_domain)| raw ~ '</a>' %}
{% set prototypeHtml = prototypeHtml ~ '</div>' %}
{% endif %}
{% set prototypeHtml = prototypeHtml ~ '</div>' %}
<div class="form-collection" prototype-control="{{ form.vars.id|camel_case }}Prototype" data-collection-prototype="{{ prototypeHtml|e('html') }}">
{% for field in form %}
<div class="prototype-row" data-row="{{ field.vars.name }}">
{{ form_widget(field) }}
{{ form_errors(field) }}
{% if allow_delete is defined and allow_delete %}
<div class="input-action input-action-delete">
<a href="#" class="btn btn-secondary btn-destructive btn-small prototype-remove" ng-click="{{ form.vars.id|camel_case }}Prototype.remove($event)" data-field="{{ field.vars.id|camel_case }}">{{ deleteButtonText|trans({}, translation_domain)| raw }}</a>
</div>
{% endif %}
</div>
{% endfor %}
<div class="prototype-container"></div>
{% if allow_add is defined and allow_add %}
<div class="input-action input-action-add">
<a href="#" class="btn btn-secondary btn-small" ng-click="{{ form.vars.id|camel_case }}Prototype.add($event)" data-collection="{{ form.vars.id|camel_case }}">{{ form.vars.addButtonText|trans({}, translation_domain) }}</a>
</div>
{% endif %}
{{ form_errors(form) }}
</div>
{% else %}
{{- block('form_widget') -}}
{% endif %}
{%- endblock collection_widget -%}
다음은 제가 테스트중인 paricular 컬렉션의 실제 템플릿입니다.
<div class="prototype-row" data-row="__name__">
<div id="proposal_recipients___name__Container">
<div class="form-item form-item-contact">
<div id="proposal_recipients___name___contactContainer">
<div class="form-item form-item-first-name"><label class="control-label required"
for="proposalRecipientsNameContactFirstName">First
Name<span class="field-required">*</span></label>
<input type="text" id="proposalRecipientsNameContactFirstName"
name="proposal[recipients][__name__][contact][firstName]" required="required"
ng-model="proposalDetails.proposal.recipients[__name__]._contact.firstName"
ng-init="proposalDetails.proposal.recipients[__name__]._contact.firstName=''" class="input"/>
</div>
<div class="form-item form-item-last-name"><label class="control-label required"
for="proposalRecipientsNameContactLastName">Last
Name<span class="field-required">*</span></label>
<input type="text" id="proposalRecipientsNameContactLastName"
name="proposal[recipients][__name__][contact][lastName]" required="required"
ng-model="proposalDetails.proposal.recipients[__name__]._contact.lastName"
ng-init="proposalDetails.proposal.recipients[__name__]._contact.lastName=''" class="input"/>
</div>
<div class="form-item form-item-email"><label class="control-label required"
for="proposalRecipientsNameContactEmail">Email
Address<span class="field-required">*</span></label> <input type="email"
id="proposalRecipientsNameContactEmail"
name="proposal[recipients][__name__][contact][email]"
required="required"
ng-model="proposalDetails.proposal.recipients[__name__]._contact.email"
ng-init="proposalDetails.proposal.recipients[__name__]._contact.email=''"
class="input"/></div>
<div class="form-item form-item-phone"><label class="control-label"
for="proposalRecipientsNameContactPhone">Phone</label>
<input type="phone" id="proposalRecipientsNameContactPhone"
name="proposal[recipients][__name__][contact][phone]"
ng-model="proposalDetails.proposal.recipients[__name__]._contact.phone"
ng-init="proposalDetails.proposal.recipients[__name__]._contact.phone=''" class="input"/>
</div>
</div>
</div>
<div class="form-item form-item-company"><label class="control-label required"
for="proposalRecipientsNameCompany">Company<span
class="field-required">*</span></label>
<input type="text" id="proposalRecipientsNameCompany" name="proposal[recipients][__name__][company]"
required="required" ng-model="proposalDetails.proposal.recipients[__name__]._company"
ng-init="proposalDetails.proposal.recipients[__name__]._company=''" class="input"/>
</div>
<div class="form-item form-item-title"><label class="control-label required" for="proposalRecipientsNameTitle">Title<span
class="field-required">*</span></label>
<input type="text" id="proposalRecipientsNameTitle" name="proposal[recipients][__name__][title]"
required="required" ng-model="proposalDetails.proposal.recipients[__name__]._title"
ng-init="proposalDetails.proposal.recipients[__name__]._title=''" class="input"/>
</div>
<div class="form-item form-item-role"><label class="control-label required" for="proposalRecipientsNameRole">Role<span
class="field-required">*</span></label>
<select id="proposalRecipientsNameRole" name="proposal[recipients][__name__][role]" required="required"
ng-model="proposalDetails.proposal.recipients[__name__]._role"
ng-init="proposalDetails.proposal.recipients[__name__]._role=''" class="hide-search"
data-show-search="0" chosen="chosen" data-allow-single-deselect="true" data-placeholder="Select"
tabindex="-1">
<option value="" selected="selected">Select</option>
<option value="ROLE_PROPOSAL_SIGNER">Signer</option>
<option value="ROLE_PROPOSAL_READER">Reader</option>
</select>
</div>
</div>
<div class="input-action input-action-delete"><a href="#"
class="btn btn-secondary btn-destructive btn-small prototype-remove"
ng-click="proposalRecipientsPrototype.remove($event)"
data-field="proposalRecipientsName">Remove Recipient</a></div>
</div>
난 아직 답을 찾으려면이를 통해 쾅거야 :이 동적으로 add()
방법으로 DOM에 추가됩니다 data-collection-prototype
의 내용이다. 알아 내면 여기서 다시 게시 할 것입니다.
누군가가 이걸 한두 번 뛰었습니다.
감사합니다.
누가 아래로 질문을 투표합니까? –