I am trying to add a form after shipping methods. But I am facing JQuery.Deferred exception When I remove knockout js code like if or foreach , the template is rendered but when I add if or foreach it gives error.
checkout_index_index.xml
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="checkout.root">
<arguments>
<argument name="jsLayout" xsi:type="array">
<item name="components" xsi:type="array">
<item name="checkout" xsi:type="array">
<item name="children" xsi:type="array">
<item name="steps" xsi:type="array">
<item name="children" xsi:type="array">
<item name="shipping-step" xsi:type="array">
<item name="children" xsi:type="array">
<item name="shippingAddress" xsi:type="array">
<item name="children" xsi:type="array">
<item name="shippingAdditional" xsi:type="array">
<item name="component" xsi:type="string">uiComponent</item>
<item name="displayArea" xsi:type="string">shippingAdditional</item>
<item name="children" xsi:type="array">
<item name="additional_block" xsi:type="array">
<item name="component" xsi:type="string">TLS_AwOnestepCheckoutExtended/js/view/student</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</argument>
</arguments>
</referenceBlock>
</body>
</page>
app/code/TLS/AwOnestepCheckoutExtended/view/frontend/web/js/view/student.js
define(
[
'jquery',
'underscore',
'ko',
'uiComponent',
// 'Aheadworks_OneStepCheckout/js/model/checkout-data',
'Magento_Customer/js/model/customer',
'Magento_Checkout/js/model/quote'
],
function (
$,
_,
ko,
Component,
customer,
quote
) {
'use strict';
return Component.extend({
defaults: {
template: 'TLS_AwOnestepCheckoutExtended/student'
},
isCustomerLoggedIn: customer.isLoggedIn,
isCourseForMe: true,
hasCourses: false,
customerData: customer.customerData,
courses: [],
/**
* @inheritdoc
*/
initialize: function () {
var hasNewAddress;
console.log('djjfjfjfj');
this.hasCourses = Boolean(window.checkoutConfig.hasCourses);
this.isCourseForMe = Boolean(1);
this.customerData = customer.customerData;
var coursesNewList = window.checkoutConfig.courses;
coursesNewList.forEach(function (course){
course.is_forme = ko.observable(false);
});
this.courses = coursesNewList;
console.log(this.courses);
this._super();
return this;
},
/**
* On cancel button click event event handler
*/
selectCourseForSomeOne: function(){
// console.log(this);
return
},
selectCourseForMe:function(){
//console.log(this);
},
onRenderComplete: function () {
// call your script code
$(".dobpicker").datepicker({
dateFormat:'dd/mm/yy',
changeMonth: true,
changeYear: true,
yearRange: "-80:",
maxDate: "-10Y",
onChangeMonthYear: function(year, month, inst) {
var format = inst.settings.dateFormat;
var selectedDate = new Date(inst.selectedYear,inst.selectedMonth,inst.selectedDay);
var date = $.datepicker.formatDate(format, selectedDate);
$(this).datepicker("setDate", selectedDate);
}
});
$("#customer-email").on('keyup change', function (e) {
$(this).val($(this).val().toLowerCase());
$(this).val($(this).val().replace(/s/g,''));
});
setTimeout(function() {
$("input[name='company']").parent().hide();
$('select[name="custom_attributes[buy_as_company]"]').change(function(e) {
if(this.value == 1){
$("input[name='company']").parent().show();
}
else{
$("input[name='company']").parent().hide();
}
});
}, 3000);
},
onEmailDuplicateValidate: function (data,event) {
const parent = event.currentTarget.parentNode;
//console.log(event.currentTarget.name);
var currentval = event.currentTarget.value
var name = event.currentTarget.name
var res = event.currentTarget.id.split("-");
var main_sku = data.productSKU;
// console.log($(parent).find('input[name=students[0][is_forme]]').is(':checked'));
//console.log($("input[name='students["+res[1]+"][is_forme]']").is(':checked'));
var isforme = $("input[name='students["+res[1]+"][is_forme]']").is(':checked');
// alert(res[1]);
$('.email_adress').each(function(i, obj) {
var res2 = obj.id.split("-");
var parent2 = obj.parentNode;
var sec_sku = $(this).data('productsku');
var isforme2 = $("input[name='students["+res2[1]+"][is_forme]']").is(':checked');
if(currentval == obj.value && event.currentTarget.name != obj.name ){
//console.log(currentval+'----'+obj.value+'----'+event.currentTarget.name+'---'+obj.name);
if(isforme==true && isforme2 == true){
obj.style.color = "black";
$('#emailaddr-'+res[1]).css("color", "black");
$('#errr-'+res2[1]).css("display", "none");
$('#errr-'+res[1]).css("display", "none");
return;
}
if(main_sku != sec_sku){
return;
}
obj.style.color = "red";
// $('#errr-'+res[1]).css("display", "block");
$('#errr-'+res2[1]).css("display", "block");
setTimeout(function(){
$('#errr-'+res[1]).css("display", "block");
$('#emailaddr-'+res[1]).css("color", "red");
// event.currentTarget.style.color = "red";
// $('#errr-'+res2[1]).css("display", "block");
}, 1000);
}
else{
obj.style.color = "black";
// event.currentTarget.style.color = "black";
$('#emailaddr-'+res[1]).css("color", "black");
$('#errr-'+res[1]).css("display", "none");
$('#errr-'+res2[1]).css("display", "none");
}
});
return true;
},
setIsForeMe:function(course, elem){
let customerData = customer.customerData;
var s_fname = $("[name='firstname']").val();
var s_lname = $("[name='lastname']").val();
var s_email = $("#customer-email").val();
var s_phone = $("[name='telephone']").val();
if (course.is_forme() === true)
{
const parent = elem.currentTarget.parentNode;
setTimeout(function(){
$(parent).find(".student-item-content > .email_adress").trigger('keyup');
}, 1000);
//console.log($(parent).find(".student-item-content > .email_adress"));
}
else
{
const parent = elem.currentTarget.parentNode;
var firstAddress;
for(var i in customerData.addresses){
firstAddress = customerData.addresses[i];
break;
}
// $(parent).find(".student-item-content > .email_adress").css("color", "black")
// $(parent).find(".student-item-content > .msg-email").css("display", "none")
$(parent).find(".student-item-content > .first_name").val(customerData.firstname || s_fname);
$(parent).find(".student-item-content > .last_name").val(customerData.lastname || s_lname);
$(parent).find(".student-item-content > .email_adress").val(customerData.email || s_email);
if (typeof firstAddress !="undefined")
{
$(parent).find(".student-item-content > .phone_number").val(firstAddress.telephone);
}else{
$(parent).find(".student-item-content > .phone_number").val(s_phone);
}
if (typeof customerData.dob !="undefined" && customerData.dob != '' && customerData.dob!=null){
var parts = customerData.dob.split('-');
var dmyDate = parts[2] + '/' + parts[1] + '/' + parts[0];
$(parent).find(".student-item-content > .c_dob").val(dmyDate);
}
setTimeout(function(){
$(parent).find(".student-item-content > .email_adress").trigger('keyup');
}, 1000);
}
course.is_forme( !(course.is_forme()) );
return true;
// console.log(this);
}
});
}
);
app/code/TLS/AwOnestepCheckoutExtended/view/frontend/web/template/student.html
<div class="testemail"></div>
<div class="aw-onestep-description">
<div class="more-information">
<span>Buying for yourselfss <b>?</b></span>
<div class="mytooltip">
If you are buying more than one course for yourself, then please tick the orange Boxes (This course is for me) and all the fields will automatically populate the booking forms.
</div>
</div>
<div class="more-information-2">
<span>Buying for a friend or colleague <b>?</b></span>
<div class="mytooltip">
If you are buying for more than one person, then add their details against the course that was purchased for them below in the booking form.
</div>
</div>
</div>
<!-- ko if: hasCourses -->
<div class="bookingform-title">
<h2><span>COMPLETE BOOKING FORM</span></h2>
</div>
<div class="group-content student-fields">
<!-- ko foreach: courses -->
<div class="student-item">
<div class="field choice is_forme" data-bind="click: $parent.setIsForeMe, attr: {id: $parent.domId(id)}">
<input class="checkbox" data-bind="attr: {name: 'students[' + $index() + '][is_forme]', checked: $data.is_forme}" type="checkbox" value="1" >
<label class="label">
<span data-bind="i18n: 'This Course is for me.'">This Course is for me</span>
</label>
</div>
<form id="onlyforvalidate" class="onlyforvalidate" onsubmit="event.preventDefault();">
<div class="student-item-content">
<!-- ko if: hasSessionData -->
<input type="hidden" data-bind="attr: {name: 'course_session[' + $index() + '][productId]', value: $data.productId}" >
<input type="hidden" data-bind="attr: {name: 'course_session[' + $index() + '][productSKU]', value: $data.productSKU}" >
<input type="hidden" data-bind="attr: {name: 'course_session[' + $index() + '][session_type]', value: $data.session_type}" >
<input type="hidden" data-bind="attr: {name: 'course_session[' + $index() + '][spaces]', value: $data.spaces}" >
<input type="hidden" data-bind="attr: {name: 'course_session[' + $index() + '][start_at_date]', value: $data.start_at_date}" >
<input type="hidden" data-bind="attr: {name: 'course_session[' + $index() + '][start_at_time]', value: $data.start_at_time}" >
<input type="hidden" data-bind="attr: {name: 'course_session[' + $index() + '][end_at_date]', value: $data.end_at_date}" >
<input type="hidden" data-bind="attr: {name: 'course_session[' + $index() + '][end_at_time]', value: $data.end_at_time}" >
<input type="hidden" data-bind="attr: {name: 'course_session[' + $index() + '][course_id]', value: $data.course_id}" >
<input type="hidden" data-bind="attr: {name: 'course_session[' + $index() + '][course_session_id]', value: $data.course_session_id}" >
<!-- /ko -->
<h3 style="font-weight: bold;font-size: 16px;" data-bind="text: 'Candidate ' + (1 + $index())"></h3>
<h3 style="font-size: 14px;margin-top: 8px;font-weight: bold;" data-bind="text: $data.name"></h3>
<input type="hidden" data-bind="attr: {name: 'students[' + $index() + '][course]', value: $data.name}" >
<input type="hidden" data-bind="attr: {name: 'students[' + $index() + '][productId]', value: $data.productId}" >
<input type="hidden" data-bind="attr: {name: 'course_session[' + $index() + '][productSKU]', value: $data.productSKU}" >
<input style="margin-bottom: 10px;" data-validate="{required:true}" type="text" required data-bind="attr: {name: 'students[' + $index() + '][first_name]'}" class="required first_name asteric" placeholder="First name" >
<input style="margin-bottom: 10px;" type="text" required data-bind="attr: {name: 'students[' + $index() + '][last_name]'}" class="required last_name asteric" placeholder="Last name" >
<input style="margin-bottom: 10px;" type="email" required data-bind="attr: {name: 'students[' + $index() + '][email]', 'data-productsku': $data.productSKU, id: 'emailaddr-' + $index() + ''}, event: {keyup: $parent.onEmailDuplicateValidate}" oninput="this.value = this.value.toLowerCase();this.value = this.value.replace(/s/g,'');" class="required email_adress asteric" placeholder="Email address" >
<p class="msg-email" data-bind="attr: {id: 'errr-' + $index() + ''}" style="margin-top: -16px;padding-top: -1px;color: red;display: none;">Email address already added.</p>
<input style="margin-bottom: 10px;" readonly type="text" data-bind="attr: {name: 'students[' + $index() + '][dob]'}, afterRender: $parent.onRenderComplete" placeholder="Date of Birth (dd/mm/yyyy)" class="dobpicker c_dob" >
<input style="margin-bottom: 10px;" type="text" required data-bind="attr: {name: 'students[' + $index() + '][phone]'}" class="required phone_number asteric" placeholder="Mobile number" >
<button type="submit" style="display: none;" class="chk_button">Check</button>
</div>
</form>
</div>
<!-- /ko -->
</div>
<!-- /ko -->
I am getting following error. Can anyone please help?
jQuery.Deferred exception: Unable to process binding "if: function(){return hasCourses }"
Message: Unable to process binding "foreach: function(){return courses }"
Message: Unable to process binding "attr: function(){return {id:$parent.domId(id)} }"
Message: id is not defined ReferenceError: Unable to process binding "if: function(){return hasCourses }"
Message: Unable to process binding "foreach: function(){return courses }"
Message: Unable to process binding "attr: function(){return {id:$parent.domId(id)} }"
Message: id is not defined
at attr (eval at createBindingsStringEvaluator (https://tls.mage360.co.uk/static/frontend/JohnThomas/learningstation/en_GB/knockoutjs/knockout.js:3221:28), <anonymous>:3:130)
at evaluateValueAccessor (https://tls.mage360.co.uk/static/frontend/JohnThomas/learningstation/en_GB/knockoutjs/knockout.js:3494:28)
at https://tls.mage360.co.uk/static/frontend/JohnThomas/learningstation/en_GB/knockoutjs/knockout.js:3671:44
at update (https://tls.mage360.co.uk/static/frontend/JohnThomas/learningstation/en_GB/knockoutjs/knockout.js:4429:59)
at ko.dependentObservable.disposeWhenNodeIsRemoved (https://tls.mage360.co.uk/static/frontend/JohnThomas/learningstation/en_GB/knockoutjs/knockout.js:3745:45)
at Function.evaluateImmediate_CallReadThenEndDependencyDetection (https://tls.mage360.co.uk/static/frontend/JohnThomas/learningstation/en_GB/knockoutjs/knockout.js:2331:115)
at Function.evaluateImmediate_CallReadWithDependencyDetection (https://tls.mage360.co.uk/static/frontend/JohnThomas/learningstation/en_GB/knockoutjs/knockout.js:2288:41)
at Function.evaluateImmediate (https://tls.mage360.co.uk/static/frontend/JohnThomas/learningstation/en_GB/knockoutjs/knockout.js:2253:40)
at ko.computed.ko.dependentObservable (https://tls.mage360.co.uk/static/frontend/JohnThomas/learningstation/en_GB/knockoutjs/knockout.js:2085:40)
at https://tls.mage360.co.uk/static/frontend/JohnThomas/learningstation/en_GB/knockoutjs/knockout.js:3743:40 undefined