Bug 1429180 - Option to use a new billing address when adding a new payment method. r=MattN
authorJared Wein <jwein@mozilla.com>
Thu, 10 May 2018 15:12:01 -0400
changeset 419310 02cc06146058af4f5332d288fd169edd1f2c77a3
parent 419309 2676c42417378e19b03128be7343ec803f722502
child 419311 88f302c4a1eb30e05f6de319bb755a94f6e0343d
push id34036
push userdluca@mozilla.com
push dateWed, 23 May 2018 09:50:27 +0000
treeherdermozilla-central@bdb0b4d7712d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1429180
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1429180 - Option to use a new billing address when adding a new payment method. r=MattN MozReview-Commit-ID: 5LrpUw1LdT3
browser/components/payments/content/paymentDialogWrapper.js
browser/components/payments/res/containers/address-form.js
browser/components/payments/res/containers/address-picker.js
browser/components/payments/res/containers/basic-card-form.js
browser/components/payments/res/containers/payment-method-picker.js
browser/components/payments/res/mixins/PaymentStateSubscriberMixin.js
browser/components/payments/res/paymentRequest.js
browser/components/payments/res/paymentRequest.xhtml
browser/components/payments/test/browser/browser_address_edit.js
browser/components/payments/test/browser/browser_card_edit.js
browser/components/payments/test/mochitest/test_address_form.html
browser/components/payments/test/mochitest/test_basic_card_form.html
browser/extensions/formautofill/content/autofillEditForms.js
--- a/browser/components/payments/content/paymentDialogWrapper.js
+++ b/browser/components/payments/content/paymentDialogWrapper.js
@@ -577,16 +577,21 @@ var paymentDialogWrapper = {
 
       // Select the new record
       if (selectedStateKey) {
         Object.assign(successStateChange, {
           [selectedStateKey]: guid,
         });
       }
 
+      const pageId = collectionName == "creditCards" ?
+                                   "basic-card-page" :
+                                   "address-page";
+      successStateChange[pageId].guid = guid;
+
       this.sendMessageToContent("updateState", successStateChange);
     } catch (ex) {
       this.sendMessageToContent("updateState", errorStateChange);
     }
   },
 
   /**
    * @implements {nsIObserver}
--- a/browser/components/payments/res/containers/address-form.js
+++ b/browser/components/payments/res/containers/address-form.js
@@ -81,48 +81,49 @@ export default class AddressForm extends
       super.connectedCallback();
     });
   }
 
   render(state) {
     let record = {};
     let {
       page,
+      "address-page": addressPage,
     } = state;
 
     if (this.id && page && page.id !== this.id) {
       log.debug(`AddressForm: no need to further render inactive page: ${page.id}`);
       return;
     }
 
     this.cancelButton.textContent = this.dataset.cancelButtonLabel;
     this.backButton.textContent = this.dataset.backButtonLabel;
     this.saveButton.textContent = this.dataset.saveButtonLabel;
     this.persistCheckbox.label = this.dataset.persistCheckboxLabel;
 
     this.backButton.hidden = page.onboardingWizard;
     this.cancelButton.hidden = !page.onboardingWizard;
 
-    if (page.addressFields) {
-      this.setAttribute("address-fields", page.addressFields);
+    if (addressPage.addressFields) {
+      this.setAttribute("address-fields", addressPage.addressFields);
     } else {
       this.removeAttribute("address-fields");
     }
 
-    this.pageTitle.textContent = page.title;
+    this.pageTitle.textContent = addressPage.title;
     this.genericErrorText.textContent = page.error;
 
-    let editing = !!page.guid;
+    let editing = !!addressPage.guid;
     let addresses = paymentRequest.getAddresses(state);
 
     // If an address is selected we want to edit it.
     if (editing) {
-      record = addresses[page.guid];
+      record = addresses[addressPage.guid];
       if (!record) {
-        throw new Error("Trying to edit a non-existing address: " + page.guid);
+        throw new Error("Trying to edit a non-existing address: " + addressPage.guid);
       }
       // When editing an existing record, prevent changes to persistence
       this.persistCheckbox.hidden = true;
     } else {
       // Adding a new record: default persistence to checked when in a not-private session
       this.persistCheckbox.hidden = false;
       this.persistCheckbox.checked = !state.isPrivate;
     }
@@ -141,21 +142,29 @@ export default class AddressForm extends
 
   onClick(evt) {
     switch (evt.target) {
       case this.cancelButton: {
         paymentRequest.cancel();
         break;
       }
       case this.backButton: {
-        this.requestStore.setState({
+        let currentState = this.requestStore.getState();
+        const previousId = currentState.page.previousId;
+        let state = {
           page: {
-            id: "payment-summary",
+            id: previousId || "payment-summary",
           },
-        });
+        };
+        if (previousId) {
+          state[previousId] = Object.assign({}, currentState[previousId], {
+            preserveFieldValues: true,
+          });
+        }
+        this.requestStore.setState(state);
         break;
       }
       case this.saveButton: {
         this.saveRecord();
         break;
       }
       default: {
         throw new Error("Unexpected click target");
@@ -164,48 +173,61 @@ export default class AddressForm extends
   }
 
   saveRecord() {
     let record = this.formHandler.buildFormObject();
     let {
       page,
       tempAddresses,
       savedBasicCards,
+      "address-page": addressPage,
+      "basic-card-page": basicCardPage,
     } = this.requestStore.getState();
-    let editing = !!page.guid;
+    let editing = !!addressPage.guid;
 
-    if (editing ? (page.guid in tempAddresses) : !this.persistCheckbox.checked) {
+    if (editing ? (addressPage.guid in tempAddresses) : !this.persistCheckbox.checked) {
       record.isTemporary = true;
     }
 
     let state = {
       errorStateChange: {
         page: {
           id: "address-page",
           onboardingWizard: page.onboardingWizard,
           error: this.dataset.errorGenericSave,
         },
+        "address-page": addressPage,
       },
       preserveOldProperties: true,
       selectedStateKey: page.selectedStateKey,
     };
 
     if (page.onboardingWizard && !Object.keys(savedBasicCards).length) {
       state.successStateChange = {
         page: {
           id: "basic-card-page",
-          onboardingWizard: true,
-          guid: null,
+          previousId: "address-page",
+          onboardingWizard: page.onboardingWizard,
         },
       };
     } else {
       state.successStateChange = {
         page: {
-          id: "payment-summary",
+          id: page.previousId || "payment-summary",
+          onboardingWizard: page.onboardingWizard,
         },
       };
     }
 
-    paymentRequest.updateAutofillRecord("addresses", record, page.guid, state);
+    state.successStateChange["address-page"] = addressPage;
+    state.successStateChange["basic-card-page"] = basicCardPage;
+
+    const previousId = page.previousId;
+    if (previousId) {
+      state.successStateChange[previousId].preserveFieldValues = true;
+      state.successStateChange[previousId].addressesModified = true;
+    }
+
+    paymentRequest.updateAutofillRecord("addresses", record, addressPage.guid, state);
   }
 }
 
 customElements.define("address-form", AddressForm);
--- a/browser/components/payments/res/containers/address-picker.js
+++ b/browser/components/payments/res/containers/address-picker.js
@@ -163,32 +163,34 @@ export default class AddressPicker exten
       });
     }
   }
 
   onClick({target}) {
     let nextState = {
       page: {
         id: "address-page",
+      },
+      "address-page": {
+        addressFields: this.getAttribute("address-fields"),
         selectedStateKey: this.selectedStateKey,
-        addressFields: this.getAttribute("address-fields"),
       },
     };
 
     switch (target) {
       case this.addLink: {
-        nextState.page.guid = null;
-        nextState.page.title = this.dataset.addAddressTitle;
+        nextState["address-page"].guid = null;
+        nextState["address-page"].title = this.dataset.addAddressTitle;
         break;
       }
       case this.editLink: {
         let state = this.requestStore.getState();
         let selectedAddressGUID = state[this.selectedStateKey];
-        nextState.page.guid = selectedAddressGUID;
-        nextState.page.title = this.dataset.editAddressTitle;
+        nextState["address-page"].guid = selectedAddressGUID;
+        nextState["address-page"].title = this.dataset.editAddressTitle;
         break;
       }
       default: {
         throw new Error("Unexpected onClick");
       }
     }
 
     this.requestStore.setState(nextState);
--- a/browser/components/payments/res/containers/basic-card-form.js
+++ b/browser/components/payments/res/containers/basic-card-form.js
@@ -22,16 +22,25 @@ export default class BasicCardForm exten
 
     this.pageTitle = document.createElement("h1");
     this.genericErrorText = document.createElement("div");
 
     this.cancelButton = document.createElement("button");
     this.cancelButton.className = "cancel-button";
     this.cancelButton.addEventListener("click", this);
 
+    this.addressAddLink = document.createElement("a");
+    this.addressAddLink.className = "add-link";
+    this.addressAddLink.href = "javascript:void(0)";
+    this.addressAddLink.addEventListener("click", this);
+    this.addressEditLink = document.createElement("a");
+    this.addressEditLink.className = "edit-link";
+    this.addressEditLink.href = "javascript:void(0)";
+    this.addressEditLink.addEventListener("click", this);
+
     this.backButton = document.createElement("button");
     this.backButton.className = "back-button";
     this.backButton.addEventListener("click", this);
 
     this.saveButton = document.createElement("button");
     this.saveButton.className = "save-button";
     this.saveButton.addEventListener("click", this);
 
@@ -67,77 +76,95 @@ export default class BasicCardForm exten
       let addresses = [];
       this.formHandler = new EditCreditCard({
         form,
       }, record, addresses, {
         isCCNumber: PaymentDialogUtils.isCCNumber,
         getAddressLabel: PaymentDialogUtils.getAddressLabel,
       });
 
+      let fragment = document.createDocumentFragment();
+      fragment.append(this.addressAddLink);
+      fragment.append(" ");
+      fragment.append(this.addressEditLink);
+      let billingAddressRow = this.form.querySelector(".billingAddressRow");
+      billingAddressRow.appendChild(fragment);
+
       this.appendChild(this.persistCheckbox);
       this.appendChild(this.genericErrorText);
       this.appendChild(this.cancelButton);
       this.appendChild(this.backButton);
       this.appendChild(this.saveButton);
       // Only call the connected super callback(s) once our markup is fully
       // connected, including the shared form fetched asynchronously.
       super.connectedCallback();
     });
   }
 
   render(state) {
     let {
       page,
       selectedShippingAddress,
+      "basic-card-page": basicCardPage,
     } = state;
 
     if (this.id && page && page.id !== this.id) {
       log.debug(`BasicCardForm: no need to further render inactive page: ${page.id}`);
       return;
     }
 
     this.cancelButton.textContent = this.dataset.cancelButtonLabel;
     this.backButton.textContent = this.dataset.backButtonLabel;
     this.saveButton.textContent = this.dataset.saveButtonLabel;
     this.persistCheckbox.label = this.dataset.persistCheckboxLabel;
+    this.addressAddLink.textContent = this.dataset.addressAddLinkLabel;
+    this.addressEditLink.textContent = this.dataset.addressEditLinkLabel;
 
     // The back button is temporarily hidden(See Bug 1462461).
     this.backButton.hidden = !!page.onboardingWizard;
     this.cancelButton.hidden = !page.onboardingWizard;
 
     let record = {};
     let basicCards = paymentRequest.getBasicCards(state);
     let addresses = paymentRequest.getAddresses(state);
 
     this.genericErrorText.textContent = page.error;
 
-    let editing = !!page.guid;
+    let editing = !!basicCardPage.guid;
     this.form.querySelector("#cc-number").disabled = editing;
 
     // If a card is selected we want to edit it.
     if (editing) {
       this.pageTitle.textContent = this.dataset.editBasicCardTitle;
-      record = basicCards[page.guid];
+      record = basicCards[basicCardPage.guid];
       if (!record) {
-        throw new Error("Trying to edit a non-existing card: " + page.guid);
+        throw new Error("Trying to edit a non-existing card: " + basicCardPage.guid);
       }
       // When editing an existing record, prevent changes to persistence
       this.persistCheckbox.hidden = true;
     } else {
       this.pageTitle.textContent = this.dataset.addBasicCardTitle;
       // Use a currently selected shipping address as the default billing address
-      if (selectedShippingAddress) {
+      if (!record.billingAddressGUID && selectedShippingAddress) {
         record.billingAddressGUID = selectedShippingAddress;
       }
       // Adding a new record: default persistence to checked when in a not-private session
       this.persistCheckbox.hidden = false;
       this.persistCheckbox.checked = !state.isPrivate;
     }
 
-    this.formHandler.loadRecord(record, addresses);
+    this.formHandler.loadRecord(record, addresses, basicCardPage.preserveFieldValues);
+
+    this.form.querySelector(".billingAddressRow").hidden = false;
+
+    if (basicCardPage.addressesModified) {
+      let addressGuid = state["address-page"].guid;
+      let billingAddressSelect = this.form.querySelector("#billingAddressGUID");
+      billingAddressSelect.value = addressGuid;
+    }
   }
 
   handleEvent(event) {
     switch (event.type) {
       case "click": {
         this.onClick(event);
         break;
       }
@@ -145,16 +172,45 @@ export default class BasicCardForm exten
   }
 
   onClick(evt) {
     switch (evt.target) {
       case this.cancelButton: {
         paymentRequest.cancel();
         break;
       }
+      case this.addressAddLink:
+      case this.addressEditLink: {
+        let {
+          "basic-card-page": basicCardPage,
+        } = this.requestStore.getState();
+        let nextState = {
+          page: {
+            id: "address-page",
+            previousId: "basic-card-page",
+          },
+          "address-page": {
+            guid: null,
+            title: this.dataset.billingAddressTitleAdd,
+          },
+          "basic-card-page": {
+            preserveFieldValues: true,
+            guid: basicCardPage.guid,
+          },
+        };
+        let billingAddressGUID = this.form.querySelector("#billingAddressGUID");
+        let selectedOption = billingAddressGUID.selectedOptions.length &&
+                             billingAddressGUID.selectedOptions[0];
+        if (evt.target == this.addressEditLink && selectedOption && selectedOption.value) {
+          nextState["address-page"].title = this.dataset.billingAddressTitleEdit;
+          nextState["address-page"].guid = selectedOption.value;
+        }
+        this.requestStore.setState(nextState);
+        break;
+      }
       case this.backButton: {
         this.requestStore.setState({
           page: {
             id: "payment-summary",
           },
         });
         break;
       }
@@ -165,47 +221,56 @@ export default class BasicCardForm exten
       default: {
         throw new Error("Unexpected click target");
       }
     }
   }
 
   saveRecord() {
     let record = this.formHandler.buildFormObject();
+    let currentState = this.requestStore.getState();
     let {
       page,
       tempBasicCards,
-    } = this.requestStore.getState();
-    let editing = !!page.guid;
+      "basic-card-page": basicCardPage,
+    } = currentState;
+    let editing = !!basicCardPage.guid;
 
-    if (editing ? (page.guid in tempBasicCards) : !this.persistCheckbox.checked) {
+    if (editing ? (basicCardPage.guid in tempBasicCards) : !this.persistCheckbox.checked) {
       record.isTemporary = true;
     }
 
     for (let editableFieldName of ["cc-name", "cc-exp-month", "cc-exp-year"]) {
       record[editableFieldName] = record[editableFieldName] || "";
     }
 
     // Only save the card number if we're saving a new record, otherwise we'd
     // overwrite the unmasked card number with the masked one.
     if (!editing) {
       record["cc-number"] = record["cc-number"] || "";
     }
 
-    paymentRequest.updateAutofillRecord("creditCards", record, page.guid, {
+    let state = {
       errorStateChange: {
         page: {
           id: "basic-card-page",
           error: this.dataset.errorGenericSave,
         },
       },
       preserveOldProperties: true,
       selectedStateKey: "selectedPaymentCard",
       successStateChange: {
         page: {
           id: "payment-summary",
         },
       },
-    });
+    };
+
+    const previousId = page.previousId;
+    if (previousId) {
+      state.successStateChange[previousId] = Object.assign({}, currentState[previousId]);
+    }
+
+    paymentRequest.updateAutofillRecord("creditCards", record, basicCardPage.guid, state);
   }
 }
 
 customElements.define("basic-card-form", BasicCardForm);
--- a/browser/components/payments/res/containers/payment-method-picker.js
+++ b/browser/components/payments/res/containers/payment-method-picker.js
@@ -128,27 +128,28 @@ export default class PaymentMethodPicker
     this.requestStore.setState(stateChange);
   }
 
   onClick({target}) {
     let nextState = {
       page: {
         id: "basic-card-page",
       },
+      "basic-card-page": {},
     };
 
     switch (target) {
       case this.addLink: {
-        nextState.page.guid = null;
+        nextState["basic-card-page"].guid = null;
         break;
       }
       case this.editLink: {
         let state = this.requestStore.getState();
         let selectedPaymentCardGUID = state[this.selectedStateKey];
-        nextState.page.guid = selectedPaymentCardGUID;
+        nextState["basic-card-page"].guid = selectedPaymentCardGUID;
         break;
       }
       default: {
         throw new Error("Unexpected onClick");
       }
     }
 
     this.requestStore.setState(nextState);
--- a/browser/components/payments/res/mixins/PaymentStateSubscriberMixin.js
+++ b/browser/components/payments/res/mixins/PaymentStateSubscriberMixin.js
@@ -10,20 +10,31 @@ import PaymentsStore from "../PaymentsSt
 
 /**
  * State of the payment request dialog.
  */
 export let requestStore = new PaymentsStore({
   changesPrevented: false,
   completionState: "initial",
   orderDetailsShowing: false,
+  "basic-card-page": {
+    guid: null,
+    // preserveFieldValues: true,
+  },
+  "address-page": {
+    guid: null,
+    title: "",
+  },
+  "payment-summary": {
+  },
   page: {
     id: "payment-summary",
+    previousId: null,
     // onboardingWizard: true,
-    // error: "My error",
+    // error: "",
   },
   request: {
     tabId: null,
     topLevelPrincipal: {URI: {displayHost: null}},
     requestId: null,
     paymentMethods: [],
     paymentDetails: {
       id: null,
--- a/browser/components/payments/res/paymentRequest.js
+++ b/browser/components/payments/res/paymentRequest.js
@@ -129,17 +129,16 @@ var paymentRequest = {
       state.page = {
         id: "address-page",
         onboardingWizard: true,
       };
     } else if (Object.keys(detail.savedBasicCards).length == 0) {
       state.page = {
         id: "basic-card-page",
         onboardingWizard: true,
-        guid: null,
       };
     }
 
     document.querySelector("payment-dialog").setStateFromParent(state);
   },
 
   cancel() {
     this.sendMessageToChrome("paymentCancel");
--- a/browser/components/payments/res/paymentRequest.xhtml
+++ b/browser/components/payments/res/paymentRequest.xhtml
@@ -20,30 +20,34 @@
   <!ENTITY payer.addLink.label        "Add">
   <!ENTITY payer.editLink.label       "Edit">
   <!ENTITY shippingAddress.addPage.title  "Add Shipping Address">
   <!ENTITY shippingAddress.editPage.title "Edit Shipping Address">
   <!ENTITY deliveryAddress.addPage.title  "Add Delivery Address">
   <!ENTITY deliveryAddress.editPage.title "Edit Delivery Address">
   <!ENTITY pickupAddress.addPage.title    "Add Pickup Address">
   <!ENTITY pickupAddress.editPage.title   "Edit Pickup Address">
+  <!ENTITY billingAddress.addPage.title   "Add Billing Address">
+  <!ENTITY billingAddress.editPage.title  "Edit Billing Address">
   <!ENTITY basicCard.addPage.title    "Add Credit Card">
   <!ENTITY basicCard.editPage.title   "Edit Credit Card">
   <!ENTITY payer.addPage.title        "Add Payer Contact">
   <!ENTITY payer.editPage.title       "Edit Payer Contact">
   <!ENTITY payerLabel                 "Contact Information">
   <!ENTITY cancelPaymentButton.label   "Cancel">
   <!ENTITY approvePaymentButton.label  "Pay">
   <!ENTITY processingPaymentButton.label "Processing">
   <!ENTITY successPaymentButton.label    "Done">
   <!ENTITY failPaymentButton.label       "Fail">
   <!ENTITY unknownPaymentButton.label    "Unknown">
   <!ENTITY orderDetailsLabel          "Order Details">
   <!ENTITY orderTotalLabel            "Total">
   <!ENTITY basicCardPage.error.genericSave    "There was an error saving the payment card.">
+  <!ENTITY basicCardPage.addressAddLink.label "Add">
+  <!ENTITY basicCardPage.addressEditLink.label "Edit">
   <!ENTITY basicCardPage.backButton.label     "Back">
   <!ENTITY basicCardPage.saveButton.label     "Save">
   <!ENTITY basicCardPage.persistCheckbox.label     "Save credit card to Firefox (Security code will not be saved)">
   <!ENTITY addressPage.error.genericSave      "There was an error saving the address.">
   <!ENTITY addressPage.cancelButton.label     "Cancel">
   <!ENTITY addressPage.backButton.label       "Back">
   <!ENTITY addressPage.saveButton.label       "Save">
   <!ENTITY addressPage.persistCheckbox.label  "Save address to Firefox">
@@ -133,16 +137,20 @@
         <order-details></order-details>
       </section>
 
       <basic-card-form id="basic-card-page"
                        class="page"
                        data-add-basic-card-title="&basicCard.addPage.title;"
                        data-edit-basic-card-title="&basicCard.editPage.title;"
                        data-error-generic-save="&basicCardPage.error.genericSave;"
+                       data-address-add-link-label="&basicCardPage.addressAddLink.label;"
+                       data-address-edit-link-label="&basicCardPage.addressEditLink.label;"
+                       data-billing-address-title-add="&billingAddress.addPage.title;"
+                       data-billing-address-title-edit="&billingAddress.editPage.title;"
                        data-back-button-label="&basicCardPage.backButton.label;"
                        data-save-button-label="&basicCardPage.saveButton.label;"
                        data-cancel-button-label="&cancelPaymentButton.label;"
                        data-persist-checkbox-label="&basicCardPage.persistCheckbox.label;"
                        hidden="hidden"></basic-card-form>
 
       <address-form id="address-page"
                     class="page"
--- a/browser/components/payments/test/browser/browser_address_edit.js
+++ b/browser/components/payments/test/browser/browser_address_edit.js
@@ -49,25 +49,25 @@ add_task(async function test_add_link() 
       }, "No saved addresses when starting test");
 
       let addLink = content.document.querySelector("address-picker .add-link");
       is(addLink.textContent, "Add", "Add link text");
 
       addLink.click();
 
       state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "address-page" && !state.page.guid;
+        return state.page.id == "address-page" && !state["address-page"].guid;
       }, "Check add page state");
 
       let title = content.document.querySelector("address-form h1");
       is(title.textContent, "Add Shipping Address", "Page title should be set");
 
-      let persistInput = content.document.querySelector("address-form labelled-checkbox");
-      ok(!persistInput.hidden, "checkbox should be visible when adding a new address");
-      ok(Cu.waiveXrays(persistInput).checked, "persist checkbox should be checked by default");
+      let persistCheckbox = content.document.querySelector("address-form labelled-checkbox");
+      ok(!persistCheckbox.hidden, "checkbox should be visible when adding a new address");
+      ok(Cu.waiveXrays(persistCheckbox).checked, "persist checkbox should be checked by default");
 
       info("filling fields");
       for (let [key, val] of Object.entries(address)) {
         let field = content.document.getElementById(key);
         if (!field) {
           ok(false, `${key} field not found`);
         }
         field.value = val;
@@ -140,24 +140,24 @@ add_task(async function test_edit_link()
       Cu.waiveXrays(picker).dropdown.popupBox.children[0].click();
 
       let editLink = content.document.querySelector("address-picker .edit-link");
       is(editLink.textContent, "Edit", "Edit link text");
 
       editLink.click();
 
       state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "address-page" && !!state.page.guid;
+        return state.page.id == "address-page" && !!state["address-page"].guid;
       }, "Check edit page state");
 
       let title = content.document.querySelector("address-form h1");
       is(title.textContent, "Edit Shipping Address", "Page title should be set");
 
-      let persistInput = content.document.querySelector("address-form labelled-checkbox");
-      ok(persistInput.hidden, "checkbox should be hidden when editing an address");
+      let persistCheckbox = content.document.querySelector("address-form labelled-checkbox");
+      ok(persistCheckbox.hidden, "checkbox should be hidden when editing an address");
 
       info("overwriting field values");
       for (let [key, val] of Object.entries(address)) {
         let field = content.document.getElementById(key);
         field.value = val;
         ok(!field.disabled, `Field #${key} shouldn't be disabled`);
       }
 
@@ -225,25 +225,25 @@ add_task(async function test_add_payer_c
       }, "No saved addresses when starting test");
 
       let addLink = content.document.querySelector("address-picker.payer-related .add-link");
       is(addLink.textContent, "Add", "Add link text");
 
       addLink.click();
 
       state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "address-page" && !state.page.guid;
+        return state.page.id == "address-page" && !state["address-page"].guid;
       }, "Check add page state");
 
       let title = content.document.querySelector("address-form h1");
       is(title.textContent, "Add Payer Contact", "Page title should be set");
 
-      let persistInput = content.document.querySelector("address-form labelled-checkbox");
-      ok(!persistInput.hidden, "checkbox should be visible when adding a new address");
-      ok(Cu.waiveXrays(persistInput).checked, "persist checkbox should be checked by default");
+      let persistCheckbox = content.document.querySelector("address-form labelled-checkbox");
+      ok(!persistCheckbox.hidden, "checkbox should be visible when adding a new address");
+      ok(Cu.waiveXrays(persistCheckbox).checked, "persist checkbox should be checked by default");
 
       info("filling fields");
       for (let [key, val] of Object.entries(address)) {
         let field = content.document.getElementById(key);
         if (!field) {
           ok(false, `${key} field not found`);
         }
         field.value = val;
@@ -312,25 +312,24 @@ add_task(async function test_edit_payer_
 
       let editLink =
         content.document.querySelector("address-picker.payer-related .edit-link");
       is(editLink.textContent, "Edit", "Edit link text");
 
       editLink.click();
 
       state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        info("state.page.id: " + state.page.id + "; state.page.guid: " + state.page.guid);
-        return state.page.id == "address-page" && !!state.page.guid;
+        return state.page.id == "address-page" && !!state["address-page"].guid;
       }, "Check edit page state");
 
       let title = content.document.querySelector("address-form h1");
       is(title.textContent, "Edit Payer Contact", "Page title should be set");
 
-      let persistInput = content.document.querySelector("address-form labelled-checkbox");
-      ok(persistInput.hidden, "checkbox should be hidden when editing an address");
+      let persistCheckbox = content.document.querySelector("address-form labelled-checkbox");
+      ok(persistCheckbox.hidden, "checkbox should be hidden when editing an address");
 
       info("overwriting field values");
       for (let [key, val] of Object.entries(address)) {
         let field = content.document.getElementById(key);
         field.value = val + "1";
         ok(!field.disabled, `Field #${key} shouldn't be disabled`);
       }
 
@@ -432,19 +431,20 @@ add_task(async function test_private_per
     // add an address
     // (return to summary view)
     info("add an address");
     await spawnPaymentDialogTask(frame, async () => {
       let {
         PaymentTestUtils: PTU,
       } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
 
-      let persistInput = content.document.querySelector("address-form labelled-checkbox");
-      ok(!persistInput.hidden, "checkbox should be visible when adding a new address");
-      ok(!Cu.waiveXrays(persistInput).checked, "persist checkbox should be unchecked by default");
+      let persistCheckbox = content.document.querySelector("address-form labelled-checkbox");
+      ok(!persistCheckbox.hidden, "checkbox should be visible when adding a new address");
+      ok(!Cu.waiveXrays(persistCheckbox).checked,
+         "persist checkbox should be unchecked by default");
 
       info("add the temp address");
       let addressToAdd = PTU.Addresses.Temp;
       for (let [key, val] of Object.entries(addressToAdd)) {
         let field = content.document.getElementById(key);
         field.value = val;
       }
       content.document.querySelector("address-form button:last-of-type").click();
--- a/browser/components/payments/test/browser/browser_card_edit.js
+++ b/browser/components/payments/test/browser/browser_card_edit.js
@@ -13,55 +13,128 @@ add_task(async function test_add_link() 
     } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
 
     let addLink = content.document.querySelector("payment-method-picker .add-link");
     is(addLink.textContent, "Add", "Add link text");
 
     addLink.click();
 
     let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !state.page.guid;
+      return state.page.id == "basic-card-page" && !state["basic-card-page"].guid;
     }, "Check add page state");
 
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return Object.keys(state.savedBasicCards).length == 0 &&
+             Object.keys(state.savedAddresses).length == 0;
+    }, "Check no cards or addresses present at beginning of test");
+
     let title = content.document.querySelector("basic-card-form h1");
     is(title.textContent, "Add Credit Card", "Add title should be set");
 
     ok(!state.isPrivate,
        "isPrivate flag is not set when paymentrequest is shown from a non-private session");
-    let persistInput = content.document.querySelector("basic-card-form labelled-checkbox");
-    ok(Cu.waiveXrays(persistInput).checked, "persist checkbox should be checked by default");
+    let persistCheckbox = content.document.querySelector("basic-card-form labelled-checkbox");
+    ok(Cu.waiveXrays(persistCheckbox).checked, "persist checkbox should be checked by default");
 
     let year = (new Date()).getFullYear();
     let card = {
       "cc-number": "4111111111111111",
       "cc-name": "J. Smith",
       "cc-exp-month": 11,
       "cc-exp-year": year,
     };
 
     info("filling fields");
     for (let [key, val] of Object.entries(card)) {
       let field = content.document.getElementById(key);
       field.value = val;
       ok(!field.disabled, `Field #${key} shouldn't be disabled`);
     }
 
+    let billingAddressSelect = content.document.querySelector("#billingAddressGUID");
+    isnot(billingAddressSelect.getBoundingClientRect().height, 0,
+          "The billing address selector should always be visible");
+    is(billingAddressSelect.childElementCount, 1,
+       "Only one child option should exist by default");
+    is(billingAddressSelect.children[0].value, "",
+       "The only option should be the blank/empty option");
+
+    let addressAddLink = content.document.querySelector(".billingAddressRow .add-link");
+    addressAddLink.click();
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return state.page.id == "address-page" && !state["address-page"].guid;
+    }, "Check address page state");
+
+    let addressTitle = content.document.querySelector("address-form h1");
+    is(addressTitle.textContent, "Add Billing Address",
+       "Address on add address page should be correct");
+
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return Object.keys(state.savedBasicCards).length == 0;
+    }, "Check card was not added when clicking the 'add' address button");
+
+    let addressBackButton = content.document.querySelector("address-form .back-button");
+    addressBackButton.click();
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return state.page.id == "basic-card-page" && !state["basic-card-page"].guid &&
+             Object.keys(state.savedAddresses).length == 0;
+    }, "Check basic-card page, but card should not be saved and no addresses present");
+
+    is(title.textContent, "Add Credit Card", "Add title should be still be on credit card page");
+
+    for (let [key, val] of Object.entries(card)) {
+      let field = content.document.getElementById(key);
+      is(field.value, val, "Field should still have previous value entered");
+      ok(!field.disabled, "Fields should still be enabled for editing");
+    }
+
+    addressAddLink.click();
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return state.page.id == "address-page" && !state["address-page"].guid;
+    }, "Check address page state");
+
+    info("filling address fields");
+    for (let [key, val] of Object.entries(PTU.Addresses.TimBL)) {
+      let field = content.document.getElementById(key);
+      if (!field) {
+        ok(false, `${key} field not found`);
+      }
+      field.value = val;
+      ok(!field.disabled, `Field #${key} shouldn't be disabled`);
+    }
+
+    content.document.querySelector("address-form button:last-of-type").click();
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return state.page.id == "basic-card-page" && !state["basic-card-page"].guid &&
+             Object.keys(state.savedAddresses).length == 1;
+    }, "Check address was added and we're back on basic-card page (add)");
+
+    is(billingAddressSelect.childElementCount, 2,
+       "Two options should exist in the billingAddressSelect");
+    let selectedOption =
+      billingAddressSelect.children[billingAddressSelect.selectedIndex];
+    let selectedAddressGuid = selectedOption.value;
+    is(selectedAddressGuid, Object.values(state.savedAddresses)[0].guid,
+       "The select should have the new address selected");
+
     content.document.querySelector("basic-card-form button:last-of-type").click();
 
     state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       return Object.keys(state.savedBasicCards).length == 1;
-    }, "Check card was added");
+    }, "Check card was not added again");
 
     let cardGUIDs = Object.keys(state.savedBasicCards);
     is(cardGUIDs.length, 1, "Check there is one card");
     let savedCard = state.savedBasicCards[cardGUIDs[0]];
     card["cc-number"] = "************1111"; // Card should be masked
     for (let [key, val] of Object.entries(card)) {
       is(savedCard[key], val, "Check " + key);
     }
+    is(savedCard.billingAddressGUID, selectedAddressGuid,
+       "The saved card should be associated with the billing address");
 
     state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       return state.page.id == "payment-summary";
     }, "Switched back to payment-summary");
   }, args);
 });
 
 add_task(async function test_edit_link() {
@@ -75,19 +148,24 @@ add_task(async function test_edit_link()
     } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
 
     let editLink = content.document.querySelector("payment-method-picker .edit-link");
     is(editLink.textContent, "Edit", "Edit link text");
 
     editLink.click();
 
     let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !!state.page.guid;
+      return state.page.id == "basic-card-page" && state["basic-card-page"].guid;
     }, "Check edit page state");
 
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return Object.keys(state.savedBasicCards).length == 1 &&
+             Object.keys(state.savedAddresses).length == 1;
+    }, "Check card and address present at beginning of test");
+
     let title = content.document.querySelector("basic-card-form h1");
     is(title.textContent, "Edit Credit Card", "Edit title should be set");
 
     let nextYear = (new Date()).getFullYear() + 1;
     let card = {
       // cc-number cannot be modified
       "cc-name": "A. Nonymous",
       "cc-exp-month": 3,
@@ -97,16 +175,100 @@ add_task(async function test_edit_link()
     info("overwriting field values");
     for (let [key, val] of Object.entries(card)) {
       let field = content.document.getElementById(key);
       field.value = val;
       ok(!field.disabled, `Field #${key} shouldn't be disabled`);
     }
     ok(content.document.getElementById("cc-number").disabled, "cc-number field should be disabled");
 
+    let billingAddressSelect = content.document.querySelector("#billingAddressGUID");
+    is(billingAddressSelect.childElementCount, 2,
+       "Two options should exist in the billingAddressSelect");
+    is(billingAddressSelect.selectedIndex, 1,
+       "The billing address set by the previous test should be selected by default");
+
+    info("Test clicking 'edit' on the empty option first");
+    billingAddressSelect.selectedIndex = 0;
+
+    let addressEditLink = content.document.querySelector(".billingAddressRow .edit-link");
+    addressEditLink.click();
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return state.page.id == "address-page" && !state["address-page"].guid;
+    }, "Clicking edit button when the empty option is selected will go to 'add' page (no guid)");
+
+    let addressTitle = content.document.querySelector("address-form h1");
+    is(addressTitle.textContent, "Add Billing Address",
+       "Address on add address page should be correct");
+
+    let addressBackButton = content.document.querySelector("address-form .back-button");
+    addressBackButton.click();
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return state.page.id == "basic-card-page" && state["basic-card-page"].guid &&
+             Object.keys(state.savedAddresses).length == 1;
+    }, "Check we're back at basic-card page with no state changed after adding");
+
+    info("Go back to previously selected option before clicking 'edit' now");
+    billingAddressSelect.selectedIndex = 1;
+
+    let selectedOption = billingAddressSelect.selectedOptions.length &&
+                         billingAddressSelect.selectedOptions[0];
+    ok(selectedOption && selectedOption.value, "select should have a selected option value");
+
+    addressEditLink.click();
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return state.page.id == "address-page" && state["address-page"].guid;
+    }, "Check address page state (editing)");
+
+    is(addressTitle.textContent, "Edit Billing Address",
+       "Address on edit address page should be correct");
+
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return Object.keys(state.savedBasicCards).length == 1;
+    }, "Check card was not added again when clicking the 'edit' address button");
+
+    addressBackButton.click();
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return state.page.id == "basic-card-page" && state["basic-card-page"].guid &&
+             Object.keys(state.savedAddresses).length == 1;
+    }, "Check we're back at basic-card page with no state changed after editing");
+
+    for (let [key, val] of Object.entries(card)) {
+      let field = content.document.getElementById(key);
+      is(field.value, val, "Field should still have previous value entered");
+    }
+
+    selectedOption = billingAddressSelect.selectedOptions.length &&
+                     billingAddressSelect.selectedOptions[0];
+    ok(selectedOption && selectedOption.value, "select should have a selected option value");
+
+    addressEditLink.click();
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return state.page.id == "address-page" && state["address-page"].guid;
+    }, "Check address page state (editing)");
+
+    info("filling address fields");
+    for (let [key, val] of Object.entries(PTU.Addresses.TimBL)) {
+      let field = content.document.getElementById(key);
+      if (!field) {
+        ok(false, `${key} field not found`);
+      }
+      field.value = val + "1";
+      ok(!field.disabled, `Field #${key} shouldn't be disabled`);
+    }
+
+    content.document.querySelector("address-form button:last-of-type").click();
+    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+      return state.page.id == "basic-card-page" && state["basic-card-page"].guid &&
+             Object.keys(state.savedAddresses).length == 1;
+    }, "Check still only one address and we're back on basic-card page");
+
+    is(Object.values(state.savedAddresses)[0].tel, PTU.Addresses.TimBL.tel + "1",
+       "Check that address was edited and saved");
+
     content.document.querySelector("basic-card-form button:last-of-type").click();
 
     state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       let cards = Object.entries(state.savedBasicCards);
       return cards.length == 1 &&
              cards[0][1]["cc-name"] == card["cc-name"];
     }, "Check card was edited");
 
@@ -135,47 +297,47 @@ add_task(async function test_private_per
     } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
 
     let addLink = content.document.querySelector("payment-method-picker .add-link");
     is(addLink.textContent, "Add", "Add link text");
 
     addLink.click();
 
     let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !state.page.guid;
+      return state.page.id == "basic-card-page" && !state["basic-card-page"].guid;
     },
                                                           "Check add page state");
 
     ok(!state.isPrivate,
        "isPrivate flag is not set when paymentrequest is shown from a non-private session");
-    let persistInput = content.document.querySelector("basic-card-form labelled-checkbox");
-    ok(Cu.waiveXrays(persistInput).checked,
+    let persistCheckbox = content.document.querySelector("basic-card-form labelled-checkbox");
+    ok(Cu.waiveXrays(persistCheckbox).checked,
        "checkbox is checked by default from a non-private session");
   }, args);
 
   let privateWin = await BrowserTestUtils.openNewBrowserWindow({private: true});
   await spawnInDialogForMerchantTask(PTU.ContentTasks.createAndShowRequest, async function check() {
     let {
       PaymentTestUtils: PTU,
     } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
 
     let addLink = content.document.querySelector("payment-method-picker .add-link");
     is(addLink.textContent, "Add", "Add link text");
 
     addLink.click();
 
     let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !state.page.guid;
+      return state.page.id == "basic-card-page" && !state["basic-card-page"].guid;
     },
                                                           "Check add page state");
 
     ok(state.isPrivate,
        "isPrivate flag is set when paymentrequest is shown from a private session");
-    let persistInput = content.document.querySelector("labelled-checkbox");
-    ok(!Cu.waiveXrays(persistInput).checked,
+    let persistCheckbox = content.document.querySelector("labelled-checkbox");
+    ok(!Cu.waiveXrays(persistCheckbox).checked,
        "checkbox is not checked by default from a private session");
   }, args, {
     browser: privateWin.gBrowser,
   });
   await BrowserTestUtils.closeWindow(privateWin);
 });
 
 add_task(async function test_private_card_adding() {
@@ -190,17 +352,17 @@ add_task(async function test_private_car
     } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
 
     let addLink = content.document.querySelector("payment-method-picker .add-link");
     is(addLink.textContent, "Add", "Add link text");
 
     addLink.click();
 
     let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !state.page.guid;
+      return state.page.id == "basic-card-page" && !state["basic-card-page"].guid;
     },
                                                           "Check add page state");
 
     let savedCardCount = Object.keys(state.savedBasicCards).length;
     let tempCardCount = Object.keys(state.tempBasicCards).length;
 
     let year = (new Date()).getFullYear();
     let card = {
--- a/browser/components/payments/test/mochitest/test_address_form.html
+++ b/browser/components/payments/test/mochitest/test_address_form.html
@@ -69,17 +69,19 @@ add_task(async function test_initialStat
   form.remove();
 });
 
 add_task(async function test_backButton() {
   let form = new AddressForm();
   form.dataset.backButtonLabel = "Back";
   await form.requestStore.setState({
     page: {
-      id: "test-page",
+      id: "address-page",
+    },
+    "address-page": {
       title: "Sample page title",
     },
   });
   await form.promiseReady;
   display.appendChild(form);
   await asyncElementRendered();
 
   let stateChangePromise = promiseStateChange(form.requestStore);
@@ -133,16 +135,19 @@ add_task(async function test_saveButton(
   isDeeply(details, {
     collectionName: "addresses",
     errorStateChange: {
       page: {
         id: "address-page",
         error: "Generic error",
         onboardingWizard: undefined,
       },
+      "address-page": {
+        title: "Sample page title",
+      },
     },
     guid: undefined,
     messageType: "updateAutofillRecord",
     preserveOldProperties: true,
     record: {
       "given-name": "Jaws",
       "family-name": "Swaj",
       "organization": "Allizom",
@@ -153,16 +158,23 @@ add_task(async function test_saveButton(
       "country": "US",
       "email": "test@example.com",
       "tel": "+15555551212",
     },
     selectedStateKey: undefined,
     successStateChange: {
       page: {
         id: "payment-summary",
+        onboardingWizard: undefined,
+      },
+      "address-page": {
+        title: "Sample page title",
+      },
+      "basic-card-page": {
+        guid: null,
       },
     },
   }, "Check event details for the message to chrome");
   form.remove();
 });
 
 add_task(async function test_genericError() {
   let form = new AddressForm();
@@ -188,16 +200,18 @@ add_task(async function test_edit() {
   await asyncElementRendered();
 
   let address1 = deepClone(PTU.Addresses.TimBL);
   address1.guid = "9864798564";
 
   await form.requestStore.setState({
     page: {
       id: "address-page",
+    },
+    "address-page": {
       guid: address1.guid,
     },
     savedAddresses: {
       [address1.guid]: deepClone(address1),
     },
   });
   await asyncElementRendered();
   checkAddressForm(form, address1);
@@ -205,30 +219,33 @@ add_task(async function test_edit() {
   info("test change to minimal record");
   let minimalAddress = {
     "given-name": address1["given-name"],
     guid: "9gnjdhen46",
   };
   await form.requestStore.setState({
     page: {
       id: "address-page",
+    },
+    "address-page": {
       guid: minimalAddress.guid,
     },
     savedAddresses: {
       [minimalAddress.guid]: deepClone(minimalAddress),
     },
   });
   await asyncElementRendered();
   checkAddressForm(form, minimalAddress);
 
   info("change to no selected address");
   await form.requestStore.setState({
     page: {
       id: "address-page",
     },
+    "address-page": {},
   });
   await asyncElementRendered();
   checkAddressForm(form, {});
 
   form.remove();
 });
 
 add_task(async function test_restricted_address_fields() {
--- a/browser/components/payments/test/mochitest/test_basic_card_form.html
+++ b/browser/components/payments/test/mochitest/test_basic_card_form.html
@@ -64,17 +64,19 @@ add_task(async function test_initialStat
 });
 
 add_task(async function test_backButton() {
   let form = new BasicCardForm();
   form.dataset.backButtonLabel = "Back";
   form.dataset.addBasicCardTitle = "Sample page title 2";
   await form.requestStore.setState({
     page: {
-      id: "test-page",
+      id: "basic-card-page",
+    },
+    "basic-card-page": {
     },
   });
   await form.promiseReady;
   display.appendChild(form);
   await asyncElementRendered();
 
   let stateChangePromise = promiseStateChange(form.requestStore);
   is(form.pageTitle.textContent, "Sample page title 2", "Check title");
@@ -239,16 +241,18 @@ add_task(async function test_edit() {
   info("test year before current");
   let card1 = deepClone(PTU.BasicCards.JohnDoe);
   card1.guid = "9864798564";
   card1["cc-exp-year"] = 2011;
 
   await form.requestStore.setState({
     page: {
       id: "basic-card-page",
+    },
+    "basic-card-page": {
       guid: card1.guid,
     },
     savedBasicCards: {
       [card1.guid]: deepClone(card1),
     },
   });
   await asyncElementRendered();
   checkCCForm(form, card1);
@@ -268,30 +272,35 @@ add_task(async function test_edit() {
   let minimalCard = {
     // no expiration date or name
     "cc-number": "1234567690123",
     guid: "9gnjdhen46",
   };
   await form.requestStore.setState({
     page: {
       id: "basic-card-page",
+    },
+    "basic-card-page": {
       guid: minimalCard.guid,
     },
     savedBasicCards: {
       [minimalCard.guid]: deepClone(minimalCard),
     },
   });
   await asyncElementRendered();
   checkCCForm(form, minimalCard);
 
   info("change to no selected card");
   await form.requestStore.setState({
     page: {
       id: "basic-card-page",
     },
+    "basic-card-page": {
+      guid: null,
+    },
   });
   await asyncElementRendered();
   checkCCForm(form, {});
 
   form.remove();
 });
 </script>
 
--- a/browser/extensions/formautofill/content/autofillEditForms.js
+++ b/browser/extensions/formautofill/content/autofillEditForms.js
@@ -192,23 +192,26 @@ class EditCreditCard extends EditAutofil
       billingAddress: this._elements.form.querySelector("#billingAddressGUID"),
       billingAddressRow: this._elements.form.querySelector(".billingAddressRow"),
     });
 
     this.loadRecord(record, addresses);
     this.attachEventListeners();
   }
 
-  loadRecord(record, addresses) {
+  loadRecord(record, addresses, preserveFieldValues) {
     // _record must be updated before generateYears and generateBillingAddressOptions are called.
     this._record = record;
     this._addresses = addresses;
-    this.generateYears();
     this.generateBillingAddressOptions();
-    super.loadRecord(record);
+    if (!preserveFieldValues) {
+      // Re-generating the years will reset the selected option.
+      this.generateYears();
+      super.loadRecord(record);
+    }
   }
 
   generateYears() {
     const count = 11;
     const currentYear = new Date().getFullYear();
     const ccExpYear = this._record && this._record["cc-exp-year"];
 
     // Clear the list