UPDATE: You can access the viewmodels directly. If you need to trigger code to run after a render, use MutationObserver. I'll post my code as soon as I have a good working example.
Original Question: We have a lot of phone-in orders. I'm working on a module that auto populates the data in admin -> customer -> create new from our CRM solution using a webapi / jsonp call. This way, the data in magento does not create duplicates of data we already have stored in our 'master database'.
One task I still have left to do is add the customer's addresse(s). This seemed simple at first, until I realized how knockoutjs + magentojs is rendering everything on the customer form is blocking me from capturing templated elements. I'm having a heck of a time trying to capture the fieldsets (input elements) after after deleting all of the addresses programatically and creating new ones.
If you wonder why i'd do that, part of my code pops up a thing and goes "HEY, THIS PERSON EXISTS ALREADY. DO YOU WANT TO USE THEM?" and it removes anything you've already typed and replaces it with the correct info. Then the call center validates it, yadda yadda.
I'll share the code I have so far, but its not working quite right. FYI, this extends Abstract in order to catch the 'onUpdate' event. Don't rail me for attempting to access the collection inside of a collection item. I can't come up with a better way to catch the onUpdate event and still look at all the fields.
I also understand completely what is wrong, I just have no idea how to get around it. What is wrong is I assumed the elements generated by the .activate() call would be immediately available in the following
document.getElementsByClassName('admin__fieldset')
This is just wrong logic. Ideally, i'd LOVE to be able to pull the fieldset contents without having to resort to this UI trickery, then once i have everything set up, just render it out.
I'm not wanting to resort to jQuery hacks to watch for dom updates.
// jsonService variable is available here because it is in the php template render. see
// Stti/Customer/view/adminhtml/templates/javascriptinject.phtml
define(['ko','jquery','underscore','originalAbstract','uiElement', 'uiCollection'], function(ko, $, _, Abstract, Element, Collection) {
"use strict";
var theArray = {
formFields: [],
getKnockout: (function (ko) {
return ko;
})(ko),
addressButton: null,
populateFormFields: function () {
this.formFields = [];
// Populate the addressButton thinger
this.addressButton = this.getNewAddressButton();
var cb = (function(formFields){
return function (data) {
cr(data, formFields);
}
})(this.formFields);
var cr = function (data, formFields) {
var elems = data.elems();
for (var i = elems.length - 1; i >= 0; i--) {
if (elems[i].hasOwnProperty('uid')) {
formFields.push(elems[i]);
}
}
};
var fieldsets = document.getElementsByClassName('admin__fieldset');
for (var i = fieldsets.length - 1; i >= 0; i--) {
var data = this.getKnockout.dataFor(fieldsets[i]);
cb(data);
}
},
cleanupAddresses: function () {
// Remove all addresses
var fieldsets = document.getElementsByClassName('admin__fieldset');
for (var i = fieldsets.length - 1; i >= 0; i--) {
var data = this.getKnockout.dataFor(fieldsets[i]);
if (data.dataScope.indexOf('data.address') !== -1 && data.childType === 'group') {
data.destroy();
}
}
},
getNewAddressButton: (function () {
var retVal = null;
var customerItem = null;
// Make sure the template is loaded
var fieldsets = document.getElementsByClassName('admin__page-nav-item');
for (var i = fieldsets.length - 1; i >= 0; i--) {
var data = this.getKnockout.dataFor(fieldsets[i]);
if (data.dataScope === 'data.address') {
data.activate();
} else {
customerItem = data;
}
}
// AT THIS POINT, I REALLY WANT KNOCKOUT TO RENDER.
fieldsets = document.getElementsByClassName('admin__fieldset');
for (var i = fieldsets.length - 1; i >= 0; i--) {
var data = this.getKnockout.dataFor(fieldsets[i]);
var elems = data.elems();
if (elems.length === 1 && data.dataScope === 'data.address' && data.index === 'address') {
retVal = elems[0];
}
}
// Return the user to the Account Information section
if (customerItem !== null) {
//customerItem.activate();
}
return retVal;
}),
addNewAddress: function () {
var retVal = null;
// Use the addressButton to add a child address
if (this.addressButton) {
retVal = this.addressButton.addChild();
}
this.populateFormFields();
return retVal;
},
onUpdate: function (newValue) {
if (newValue) {
this.clearAllFields();
switch (this.index) {
case "email":
this.handleEmailBlur(newValue);
break;
case "constit_id":
this.handleConstitBlur(newValue);
break;
}
}
},
handleEmailBlur: function (newValue) {
// Don't look up anything if the box was cleared out
if (newValue != null || newValue != '') {
this.clearAllFields();
this.makeJsonReq("GetIndividualByEmail?emailaddress=" + newValue + '&callback=?');
}
},
handleConstitBlur: function (newValue) {
// Don't look up anything if the box was cleared out
if (newValue != null || newValue != '') {
this.clearAllFields();
this.makeJsonReq("GetIndividualByConstit?constit=" + newValue + '&callback=?');
}
},
jQueryByIndex: function (index) {
function findUIDbyIndex(element) {
return element.index === index;
}
return $('#' + this.formFields.find(findUIDbyIndex).uid);
},
makeJsonReq: function (callString) {
var msg = null;
$.getJSON(jsonService + callString, (function (localData) {
return function (data) {
doWork(data, localData);
}
})(this)
).done(function () {
console.log("Json Request Successful");
}).fail(function () {
console.log("Json Request Fail");
}).always(function () {
if (msg != "") {
alert(msg);
}
});
function doWork(individual, localData) {
// create as many addresses as the individual has
if (individual != null) {
if (individual.NKIUserId != null) {
if (individual.NKIUserId != "") {
msg = "WARNING! Netforum reports this user has been added to magento with ID " + individual.NKIUserId + ". LOOKUP THE CUSTOMER FIRST AND CONFIRM YOU WANT TO ADD A NEW CUSTOMER!";
}
//window.location = "/admin";
}
if (individual.ConstitID != null) {
msg = localData.populateFields(individual, localData);
}
else {
msg = "Individual could not be found in NetForum. Verify that this IS a new customer.";
}
}
else {
msg = "Customer's email was not found in netforum. Be sure to use the correct constituent ID if this is an existing customer. A new Netforum customer will be created if it is blank or incorrect.";
// prepFormNoUser("constit");
}
}
},
populateFields: function (individual, localData) {
// This function is used to get jquerySelector by index
var getField = localData.jQueryByIndex;
if (localData.jQueryByIndex('email')) {
localData.jQueryByIndex('email').val = individual.PrimaryEmailAddress;
}
var addresses = null;
var mageAddresses = [];
if (individual.Addresses) {
addresses = individual.Addresses;
// Populate the form with the addresses
for (var i = 0; i < addresses.length; i++) {
mageAddresses.push(localData.addNewAddress());
}
debugger;
var primaryAddress = null;
for (var i=0; i < addresses.length; i++) {
addresses.each(function (e) {
try {
if (e.IsPrimary) {
primaryAddress = e;
}
} catch (err) {
// todo: handle errors
}
// Populate the billing address if we are on the order screen
if (primaryAddress.Id) {
if ($('order-billing_address_cxa_key')) {
$('order-billing_address_cxa_key').value = primaryAddress.Id;
$('order-billing_address_cxa_key').disable();
}
}
if (primaryAddress.Line1) {
if ($('order-billing_address_street0')) {
$('order-billing_address_street0').value = primaryAddress.Line1;
}
}
if (primaryAddress.City) {
if ($('order-billing_address_city')) {
$('order-billing_address_city').value = primaryAddress.City;
}
}
if (primaryAddress.Zip) {
if ($('order-billing_address_postcode')) {
$('order-billing_address_postcode').value = primaryAddress.Zip;
}
}
if (individual.PrimaryPhoneNumber) {
if ($('order-billing_address_telephone')) {
$('order-billing_address_telephone').value = individual.PrimaryPhoneNumber;
}
}
});
}
}
if (individual.MemberType != null) {
if ($('group_id')) {
var options = $$('select#group_id option');
if (individual.MemberType > 0) {
options[3].selected = true;
$('signup_method').value = "ADMIN-NEWORDER-EXISTING-MEMBER";
}
else {
options[0].selected = true;
$('signup_method').value = "ADMIN-NEWORDER-EXISTING-NONMEMBER";
}
$('signup_method').disable();
}
if ($('_accountconstit_id')) {
var options = $$('select#_accountgroup_id option');
if (individual.MemberType > 0) {
options[3].selected = true;
$('_accountsignup_method').value = "ADMIN-NEWCUSTOMER-EXISTING-MEMBER";
}
else {
options[0].selected = true;
$('_accountsignup_method').value = "ADMIN-NEWCUSTOMER-EXISTING-NONMEMBER";
}
$('_accountsignup_method').disable();
}
}
if ($('_accountcst_key')) {
$('_accountcst_key').value = individual.Id;
$('_accountcst_key').disable();
}
if ($('cst_key')) {
$('cst_key').value = individual.Id;
$('cst_key').disable();
}
if (individual.FirstName) {
if ($('_accountfirstname')) {
$('_accountfirstname').value = individual.FirstName;
}
if ($('order-billing_address_firstname')) {
$('order-billing_address_firstname').value = individual.FirstName;
}
}
if (individual.LastName) {
if ($('_accountlastname')) {
$('_accountlastname').value = individual.LastName;
}
if ($('order-billing_address_lastname')) {
$('order-billing_address_lastname').value = individual.LastName;
}
}
if (individual.MiddleName) {
if ($('_accountmiddlename')) {
$('_accountmiddlename').value = individual.MiddleName;
}
if ($('order-billing_address_middlename')) {
$('order-billing_address_middlename').value = individual.MiddleName;
}
}
if (individual.DateOfBirth) {
var dob = new Date(parseInt(individual.DateOfBirth.substr(6)));
var fDob = dob.toString('MM-dd-yyyy');
if ($('_accountdob')) {
$('_accountdob').value = fDob;
}
}
return msg;
},
clearAllFields: function () {
var inputs = $(':input');
for (var i = 0; i < inputs.length; i++) {
inputs[i].value = '';
}
this.cleanupAddresses();
this.populateFormFields();
}
};
// Use jQuery to figure out what page we are on. the body will contain the class matched by name in the
// view/adminhtml/layout folder
if ($('body.customer-index-edit').length > 0) {
return Abstract.extend(theArray);
}
});