Advanced Donation Form

The Advanced Donation Form Part and accompanying REST APIs were released in version 3.0 of BBIS. They allow completely custom interfaces to be created for the donation experience, relaying the necessary information to the backend via the REST API or JavaScript SDK. For a complete list of possible options, be sure to visit the technical reference for more information.

All the examples below expect a page with a configured instance of the Advanced Donation Form Part on it. It's also important the examples below are meant to be as simple and straight-forward as possible. In a real-world scenario, we highly suggestion following standard web practices for form design, including labels for accessibility, and client-side data validation.

For all the Advanced Donation Form examples, I've split the grouped the content by language - HTML, CSS, or JS; however, when using the code in the Advanced Donation Form Part, the code is combined into a single textarea. Please be certain to wrap the content with appropriate <script> or <style> tag.

Barebones Example

In our first example, we'll create a very barebones example of a donation form, supplying only the required fields. For this example we've included no styling or error handling, other than displaying a message in the console. I've also hard-coded the designation and amount fields.

Important The DonationService constructor requires the Advanced Donation Form Part ID. In the examples below, we dynamically find this ID. You could hard-code this value if you prefer. The technique below assumes there's only one Advanced Donation Form Part per page.

<dl>
  <dt>First Name</dt>
  <dd><input type="text" id="first-name" /></dd>

  <dt>Last Name</dt>
  <dd><input type="text" id="last-name" /></dd>

  <dt>Email</dt>
  <dd><input type="text" id="email" /></dd>

  <dt>Address</dt>
  <dd><textarea id="address"></textarea></dd>

  <dt>City</dt>
  <dd><input type="text" id="city" /></dd>

  <dt>State</dt>
  <dd><input type="text" id="state" /></dd>

  <dt>Zip</dt>
  <dd><input type="text" id="zip" /></dd>

  <dt>Country</dt>
  <dd><input type="text" id="country" /></dd>
</dl>

<p><button class="btn-donate">Donate</button></p>
// Let's be good developers and not pollute the global namespace
(function($) {

  // Let's make sure the DOM is ready
  $(function() {

    // Create an instance of the DonationService
    var ds = new BLACKBAUD.api.DonationService(
      $('.BBDonationApiContainer').data('partid')
    );

    // Create the donation object we'll send
    // In order to simplify our examples, some of this information is hard-coded.
    var donation = {
      MerchantAccountId: '00000000-0000-0000-0000-000000000000',
      Gift: {
        PaymentMethod: 0,
        Designations: [
          {
            Amount: 5.00,
            DesignationId: '00000000-0000-0000-0000-000000000000'
          }
        ]
      }
    };

    // Create our success handler
    var success = function(returnedDonation) {
      console.log(returnedDonation);
    };

    // Create our error handler
    var error = function(returnedErrors) {
      console.log('Error!');
    };

    // Attach our event listener to the donate button
    $('.btn-donate').click(function(e) {

      // Stop the button from submitting the form
      e.preventDefault(); 

      // Add the information our user has typed
      donation.Donor = {
        FirstName: $('#first-name').val(),
        LastName: $('#last-name').val(),
        Address: {
          StreetAddress: $('#address').val(),
          City: $('#city').val(),
          State: $('#state').val(),
          PostalCode: $('#zip').val(),
          Country: $('#country').val()
        }
      };

      // Submit our donation
      ds.createDonation(donation, success, error);
    });

  });
}(jQuery));

Using the Payment 2.0 Part

When using the Payment 2.0 Part, the information required is reduced. For example, Donor information is should no longer be provided. Again, we're not including any styling or error handling, but I have introduced the ability to select a donation amount and designation.

<dl>
  <dt>Amount</dt>
  <dd>
    <select id="amount">
      <option value="5">5</option>
      <option value="10">10</option>
      <option value="20">20</option>
    </select>
  </dd>

  <dt>Designation</dt>
  <dd>
    <select id="designation">
      <option value="00000000-0000-0000-0000-000000000000">Example Designation 1</option>
      <option value="00000000-0000-0000-0000-000000000000">Example Designation 2</option>
    </select>
  </dd>
</dl>
      
<p><button class="btn-donate">Donate</button></p>
// Let's be good developers and not pollute the global namespace
(function($) {
  
  // Let's make sure the DOM is ready
  $(function() {
    
    // Create an instance of the DonationService
    var ds = new BLACKBAUD.api.DonationService(
      $('.BBDonationApiContainer').data('partid')
    );
    
    // Create the donation object we'll send
    // In order to simplify our examples, some of this information is hard-coded.
    var donation = {
      Gift: {
        PaymentMethod: 0,
        Designations: []
      }
    };
    
    // Create our success handler
    var success = function(returnedDonation) {
      console.log(returnedDonation);
    };
    
    // Create our error handler
    var error = function(returnedErrors) {
      console.log('Error!');
    };
    
    // Attach our event listener to the donate button
    $('.btn-donate').click(function(e) {
      
      // Stop the button from submitting the form
      e.preventDefault(); 
      
      // Add the information our user has typed
      donation.Gift.Designations.push({
        Amount: $('#amount').val(),
        DesignationId: $('#designation').val()
      });
      
      // Submit our donation
      ds.createDonation(donation, success, error);
    });
    
  });
}(jQuery));

Note The DonationService attempts to redirect to the BBSPCheckoutUri or PaymentPageUri if either of them exist (in that order) after a successful callback from the createDonation method.



Blackbaud Checkout Example

This feature can be used to configure the payment checkout pop up on ADF by using the payment's Checkout endpoints. This functionality is wrapped under Checkout Service, as shown in the example. This will enhance the end user experience and provide better troubleshooting around the missing transactions.

<!-- This div is for showing the layover after the payment completion and before the confirmation page(use when payment checkout pop up is configured)-->
<div id="bbspLoadingOverlay" class="bbspLoadingOverlay">
</div>
(function ($) {


 // Create an instance of the DonationService
  var ds = new BLACKBAUD.api.DonationService(
  $('.BBDonationApiContainer').data('partid')),
         serverMonth = $(".BBDonationApiContainer").attr("serverMonth") - 1,
         serverDay = $(".BBDonationApiContainer").attr("serverDay"),
         serverYear = $(".BBDonationApiContainer").attr("serverYear"),
         ServerDate = new Date(serverYear, serverMonth, serverDay);
		 
  var donationAmount = getDonationAmount();
        var numberOfInstallments = $("#number-of-installments").val();
        var installmentAmount = ds.getRecurringGiftInstallmentAmount(donationAmount, numberOfInstallments);
        var installmentAmt = installmentAmount;

  //Create the donation object we'll send
  //In order to simplify our examples, some of this information is hard-coded.
  var donation = {
  MerchantAccountId: '00000000-0000-0000-0000-000000000000',
  BBSPReturnUri: window.location.href,
  BBSPTemplateSitePageId: 000,
  PartId: $('.BBDonationApiContainer').data('partid'),
  Gift: {
        PaymentMethod: 0,
        Designations: []
      }
  };

  // Create our success handler
  var success = function (returnedDonation) {
  console.log(returnedDonation);
  };   

  // Create our error handler
  var error = function (returnedErrors) {
  console.log('Error!');
  };
 
//Checkout Payment popup is loaded in this form.
    if ($('form[data-formtype="bbCheckout"]').length <= 0) {
        var form = '<form method=\'get\' id=\"paymentForm\" data-formtype=\'bbCheckout\' data-disable-submit=\'false\' novalidate><\/form>';
        $('body').append(form);
    }


    $("#paymentForm").submit(function paymentComplete(e) {
        // prevent form from refreshing and show the transaction token
        e.preventDefault();
    });

	
	 var  SrtDt, publicKey, donationData, EditorContent, ServerDate,
        checkoutGenericError = "There was an error while performing the operation.The page will be refreshed";
		
	//return the donation amount	
	function getDonationAmount() {
    if ($("#amtOther").prop("checked")) {
         return $("#txtAmount").val();
    } else {
         return $("[name='radioAmount']:checked").val();
        }
    }
	
	 //Handle Generic error 
    function handleError(errorMessage) {
        $("#bbspLoadingOverlay").hide();
        alert(checkoutGenericError);
        location.reload(true);
    }

    //#region CCCheckoutPayment

	//return which payment method is selected on the page
    function GetPaymentType() {
        paymentMethod = $("[name='paymentMethod']:checked").val();
        return paymentMethod;
    }

	//set the public key by using public key service that is used to open the checkout pop up
    function GetPublicKey() {
     
    onPublicKeySuccess = function (reply) {
        publicKey = JSON.parse(reply.Data).PublicKey;
    };
    
	onPublicKeyFailure = function (d) {
    };
    
	ds.getCheckoutPublicKey(onPublicKeySuccess, onPublicKeyFailure);

    }


	//get all the information that is configured on the editor used to open the checkout pop up
    function GetEditorInformation(partId) {

        onEditorContentSuccess = function onSuccess(content) {
            donation.MerchantAccountId = content.MerchantAccountID;
            EditorContent = content;
        };

        onEditorContentFailure = function onFail(error) {
        };

        ds.getADFEditorContentInformation(partId, onEditorContentSuccess, onEditorContentFailure);

    }


    function getUrlVars(url) {
        var vars = [], hash;
        var hashes = url.slice(url.indexOf('?') + 1).split('&');
        for (var i = 0; i < hashes.length; i++) {
            hash = hashes[i].split('=');
            vars.push(hash[0]);
            vars[hash[0]] = hash[1];
        }
        return vars;
    }

	//this is the function that calls the payment api to open the checkout pop up with all the parameters
    this.makePayment = function () {
        opened = false;

        var checkout = new SecureCheckout(handleCheckoutComplete, handleCheckoutError, handleCheckoutCancelled, handleCheckoutLoaded);
        var donor = data.Donor;
		var selectedCountry=$("#country :selected").attr("iso");
		var selectedState=$("#state :selected").attr("iso");
		
		if(selectedCountry && selectedCountry=="GB")
		{
			selectedCountry="UK";
		}
        donationData = {
            "key": publicKey,
            'Amount': ($("#recMonthly").prop("checked")) ? installmentAmt : getDonationAmount(),
            'UseCaptcha': EditorContent.RecaptchRequired,
            'BillingAddressCity': donor.Address.City,
            'BillingAddressCountry': selectedCountry,
            'BillingAddressLine': donor.Address.StreetAddress,
            'BillingAddressPostCode': donor.Address.PostalCode,
            'BillingAddressState': selectedState,
            'BillingAddressEmail': donor.EmailAddress,
            'BillingAddressFirstName': donor.FirstName + " " +donor.MiddleName,
            'BillingAddressLastName': donor.LastName,
            'Cardholder': donor.FirstName + " " + donor.LastName,
            'ClientAppName': 'BBIS',
            'MerchantAccountId': EditorContent.MerchantAccountID,
            'IsEmailRequired': true,
            'PrimaryColor': EditorContent.PrimaryFontColor,
            'SecondaryColor': EditorContent.SecondaryFontColor,
            'FontFamily': EditorContent.FontType,
            'IsNameVisible': true,
          'UseVisaCheckout': EditorContent.UseVisaPass && (data.Gift && !data.Gift.Recurrence),
          'UseMasterpass': EditorContent.UseMasterPass && (data.Gift && !data.Gift.Recurrence),
          'UseApplePay': EditorContent.UseApplePay && (data.Gift && !data.Gift.Recurrence)
        };
       if (data.Gift && data.Gift.Recurrence )
		{
			donationData.CardToken = EditorContent.DataKey;
		}

        //check server date and start date here -- if same then make transaction today
        if (data.Gift && data.Gift.Recurrence && !data.Gift.Recurrence.ProcessNow) {
            return checkout.processStoredCard(donationData);
        }
        else {

            return checkout.processCardNotPresent(donationData);
        }
    }

	//to check for recurring gift that is to be processed today or not (this is check for call stored card payment api)
    function isProcessNow() {
        var recStartDate = $("#start-date").val()
        var frequency = $("#frequency").val();
        var dayOfMonth = $('#day-of-month').val();
        var dayOfWeek = $("#day-of-week").val();
        var month = $('#month').val();

        var startDateIsTodayDate = false;

        var recurrrentStartDate = new Date(recStartDate);

        var isProcessedNow = false;

        var serverDate = new Date(ServerDate);


        if (
            recurrrentStartDate.getFullYear() === serverDate.getFullYear() &&
            recurrrentStartDate.getMonth() === serverDate.getMonth() &&
            recurrrentStartDate.getDate() === serverDate.getDate()
        ) {
            startDateIsTodayDate = true;
        }
        else {

            return false;
        }

        //Weekly Frequency
        if (frequency == 1) {
            isProcessedNow = startDateIsTodayDate && dayOfWeek == serverDate.getDay();
        }
        //Mothly and Quarterly frequency
        else if (frequency == 2 || frequency == 3) {
            isProcessedNow = startDateIsTodayDate && dayOfMonth == serverDate.getDate();
        }
        //Annually frequency
        else if (frequency == 4) {

            isProcessedNow =
                startDateIsTodayDate
                && dayOfMonth == serverDate.getDate()
                && month == serverDate.getMonth() + 1;
        }
        //Every 4 weeks
        else if (frequency == 7) {
            isProcessedNow = startDateIsTodayDate;
        }
        else {
            isProcessedNow = false;
        }

        return isProcessedNow;


    };

	//when checkout popup is successfully loaded
    handleDonationCreated = function (data) {
        var orderID = JSON.parse(data.Data).OrderId;
    }

	//when checkout popup is fail to load
    this.handleDonationCreateFailed = function (error) {
        handleError(error);
    }

	//when the payment is successfully completed and we have to show the confirnmation screen
    this.handlePaymentComplete = function (data) {
        $("#bbspLoadingOverlay").hide();
        //confirmation message show here
		//donationform
        $(".form").hide();
		//confirmation div
        $(".confirmation").show();

       $(".confirmation").html(JSON.parse(data.Data).confirmationHTML);
    }

	//this function called when the checkout popup is loaded on a page
    function handleCheckoutLoaded() {

        if (!opened) {

            opened = true;
            var url = $("#bbCheckoutPaymentIframe").prop('src');
            var tid = getUrlVars(url)["t"];

            //save transaction id in global variable. Will be used throughout the transaction
            this.transactionIDl = tid;

            if (tid) {
                data.TokenId = tid;
                ds.checkoutDonationCreate(data, handleDonationCreated, handleDonationCreateFailed);
                return false;
            }
        }

        return false;
    }

	//when we cancel the payment pop up hen unbind all the binded events on checkout popup
    function UnBindPaymentCheckoutEvents() {
        $(document).unbind("checkoutComplete");
        $(document).unbind("checkoutLoaded");
        $(document).unbind("checkoutError");
        $(document).unbind("checkoutCancel");
    }

	//this is called when the payment is completed
    function handleCheckoutComplete(event, tranToken) {
        $("#bbspLoadingOverlay").show();

		var Id=tranToken ? tranToken :(event?(event.detail?(event.detail.transactionToken?event.detail.transactionToken:null):null):null);
		
        if (Id) {
            data.TokenId = Id;
            ds.checkoutDonationComplete(data, handlePaymentComplete, handleDonationCreateFailed);
        }
        else {
            handleError();
        }
		UnBindPaymentCheckoutEvents();
        return false;
    }

	//call when there is any error while doing the payment on checkout pop up
    handleCheckoutError = function (event, errorMsg, errorCode) {
        handleError(errorMsg);
    }

    //Cancel Donation if user close checkout popup
    function handleCheckoutCancelled() {
        try {
            ds.checkoutDonationCancel(data, onSuccess, onFail);
        }
        catch (e) {
            //do not store this error. Already stored from server side
        }
        UnBindPaymentCheckoutEvents();
    }

	//this function call when we click on donate button
	function sendData() {
        if (EditorContent && EditorContent.MACheckoutSupported && GetPaymentType() == 0) {
            ProcessCCPayment();
        }
    }
	
	 //use this method for credit card payment through popup
    function ProcessCCPayment() {
        
        data = donation;

            onValidationSuccess = function (result) {
            makePayment();
            return false;
        };
        onValidationFailed = function (error) {
            console.log(error);
        };

        ds.validateDonationRequest(data, onValidationSuccess, onValidationFailed);

    }
	
	//Call some functions       
        GetEditorInformation($('.BBDonationApiContainer').data('partid'));
        GetPublicKey();
		
		
	// Attach our event listener to the donate button
    $('.btn-donate').click(function(e) {
      
      // Stop the button from submitting the form
      e.preventDefault(); 
	  sendData();
	  });
		
}(jQuery));
/* css other than bootstrap */
.bbspLoadingOverlay {
width: 100%;
height: 100%;
left: 0;
top: 0;
position: fixed;
z-index: 9999999;
background-color: grey;
opacity: 0.8;
display: none;
}

Pledge Installments Example

Pledge installments are the payment donor makes for a pledge according to a defiend time schedule. The example includes the HTML required to display input fields to capture required parameters for pledge installment endpoints.

<fieldset class="donationInformation">
	<legend>
		<span class="BBListingHeading DonationListingHeading">Gift Information</span>
	</legend>
	<div>
		<input type="checkbox" id="isPaymentTwo"/> Check this box if you are using a Payment 2.0 part with this ADF
		<div class="giftAmount">
			<label class="required">Select Gift Amount:</label>
			<ul>
				<li>
					<input id="amt1000" type="radio" name="radioAmount" value="1000" />
					<label for="amt1000">
						<span class="term">Platinum</span>
						<span class="value">$1,000</span>
					</label>
				</li>
				<li>
					<input id="amt500" type="radio" name="radioAmount" value="500" />
					<label for="amt500">
						<span class="term">Gold</span>
						<span class="value">$500</span>
					</label>
				</li>
				<li>
					<input id="amt100" type="radio" name="radioAmount" value="100" />
					<label for="amt100">
						<span class="term">Silver</span>
						<span class="value">$100</span>
					</label>
				</li>
				<li>
					<input id="amt25" type="radio" name="radioAmount" value="25" />
					<label for="amt25">
						<span class="term">Bronze</span>
						<span class="value">$25</span>
					</label>
				</li>
				<li class="other">
					<input id="amtOther" type="radio" name="radioAmount" value="-1" checked="checked" />
					<label for="amtOther">
						<span class="term">Enter an amount</span>
					</label>
					<input id="txtAmount" type="text" placeholder="$" class="BBFormTextbox">
				</li>
			</ul>
		</div>
	</div>
</fieldset>
        
<!-- PLEDGE INSTALLMENT START-->
<div class="pledgeInstallments">
	<label class="required">Pledge Installment:</label>
	<ul>
		<li class="other">
			<label for="numberOfInstallments">
				Number of Installments:
			</label>
			<input id="numberOfInstallments" type="text" placeholder="$" class="BBFormTextbox">
		</li>
		<li class="other">
			Installment Amount:
			<label id="installmentAmount"/>
		</li>
		<li class="other">
			Installment End Date:
			<label id="installmentEndDate" />
		</li>
	</ul>
</div>
	<!-- PLEDGE INSTALLMENT END-->
// Let's be good developers and not pollute the global namespace
(function($) {
  
  // Let's make sure the DOM is ready
  $(function() {
    
    // Create an instance of the DonationService
    var ds = new BLACKBAUD.api.DonationService(
      $('.BBDonationApiContainer').data('partid')
    );
    
    // Create the donation object we'll send
    // In order to simplify our examples, some of this information is hard-coded.
    var donation = {
      MerchantAccountId: '00000000-0000-0000-0000-000000000000',
      Gift: {
        PaymentMethod: 0,
        Designations: [
          {
		  //Amount has been hardcoded to 500. Replace the value with a value entered by user.
            Amount: 500.00,
            DesignationId: '00000000-0000-0000-0000-000000000000'
          }
        ]
      }
    };
    
    // Create our success handler
    var success = function(returnedDonation) {
      console.log(returnedDonation);
    };
    
    // Create our error handler
    var error = function(returnedErrors) {
      console.log('Error!');
    };
    
    // Attach our event listener to the donate button
    $('.btn-donate').click(function(e) {
      
      // Stop the button from submitting the form
      e.preventDefault();
	  
      //if payment 2.0 is checked, No need to capture the donor information
       if(!isPaymentTwo){
		  donation.Donor = {
			Title: $("#title").val(),
			FirstName: $("#firstName").val(),
			LastName: $("#lastName").val(),
			EmailAddress: $("#emailAddress").val(),
			Phone: $("#phone").val(),
			Address: {
			  Country: $("#country").val(),
			  State: $("#state").val(),
			  City: $("#city").val(),
			  StreetAddress: $("#streetAddress").val(),
			  PostalCode: $("#postalCode").val()
			},
			OrganizationName: organizationName
		  };
	  }
	  
	   // PLEDGE INSTALLMENT BEGIN ********************************************************************************************************************************************************************************************************************************************************
	  var numberOfInstallments = $('#numberOfInstallments').val();
	  if (numberOfInstallments) {
	      //Amount has been hardcoded to 500. Replace the value with a value entered by user.
		  var installmentAmount = ds.getRecurringGiftInstallmentAmount(500, numberOfInstallments);
		  donation.Gift.PledgeInstallment = {
			  NumberOfInstallments: numberOfInstallments,
			  InstallmentAmount: installmentAmount
		  }
	  }
      // PLEDGE INSTALLMENT END ********************************************************************************************************************************************************************************************************************************************************
        
      // Submit our donation
      ds.createDonation(donation, success, error);
    });
    
  });
}(jQuery));

Displaying Available Countries and States

Using the Country and State endpoints, you can quickliy populate the available countries and their corresponding states. The first example uses jQuery to make an AJAX request. We also wrap this functionality in the Country and State JavaScript Service, which is shown in the second example.

<dl>
  <dt>Country</dt>
  <dd><select id="country"></select></dd>
  
  <dt>State</dt>
  <dd><select id="state"></select></dd>
</dl>
// Let's be good developers and not pollute the global namespace
(function($) {

// Let's make sure the DOM is ready
$(function() {

  var selectCountry = $('#country');
  var selectState = $('#state');
  
  // Load Countries
  $.get(BLACKBAUD.api.pageInformation.rootPath + '/webapi/country', function(countries) {
    for (var i = 0, j = countries.length; i < j; i++) {
      selectCountry.append('<option value="' + countries[i].Id + '" iso="'+countries[i].ISO+'">' + countries[i].Description + '</option>');
    }
  });
  
  // Watch Country Change
  $('#country').on('change', function() {
  
    // Load States
    $.get(BLACKBAUD.api.pageInformation.rootPath + '/webapi/country/' + $(this).val() + '/state', function(states) {
      selectState.html('');
      for (var i = 0, j = states.length; i < j; i++) {
        selectState.append('<option value="' + states[i].Id + '" iso="'+states[i].ISO+'">' + states[i].Description + '</option>');
      }
    });
  });

});
}(jQuery));

The following example uses the Country and State JavaScript Service instead of making an AJAX call directly to the endpoints.

<dl>
  <dt>Country</dt>
  <dd><select id="country"></select></dd>
  
  <dt>State</dt>
  <dd><select id="state"></select></dd>
</dl>
// Let's be good developers and not pollute the global namespace
(function($) {

// Let's make sure the DOM is ready
$(function() {

  var selectCountry = $('#country');
  var selectState = $('#state');
  var service = new BLACKBAUD.api.CountryService();
  
  // Load Countries
  service.getCountries(function(countries) {
    for (var i = 0, j = countries.length; i < j; i++) {
      selectCountry.append('<option value="' + countries[i].Id + '" iso="'+countries[i].ISO+'">' + countries[i].Description + '</option>');
    }
  });
  
  // Watch Countries Change
  $('.countries').on('change', function() {
  
    // Load States
    service.getStates($(this).val(), function(states) {
      selectState.html('');
      for (var i = 0, j = states.length; i < j; i++) {
        selectState.append('<option value="' + states[i].Id + '" iso="'+states[i].ISO+'">' + states[i].Description + '</option>');
      }
    });
  });

});
}(jQuery));

Recurrence Example

In this example, we're back to "proceeding directly to payment," as opposed to using the Payment 2.0 Part. This means we'll need to collect the donor information.

Using recurrence with the Advanced Donation Form can be a little tricky, in that the fields which are required, differs depending on the frequency of the recurrence. For example, the Month field is only valid and required if the Frequency field is set to Annually (4).

<h3>Donor Information</h3>
<dl>
  <dt>First Name</dt>
  <dd><input type="text" id="first-name" /></dd>
  
  <dt>Last Name</dt>
  <dd><input type="text" id="last-name" /></dd>
  
  <dt>Email</dt>
  <dd><input type="text" id="email" /></dd>
  
  <dt>Address</dt>
  <dd><textarea id="address"></textarea></dd>
  
  <dt>City</dt>
  <dd><input type="text" id="city" /></dd>
  
  <dt>State</dt>
  <dd><input type="text" id="state" /></dd>
  
  <dt>Zip</dt>
  <dd><input type="text" id="zip" /></dd>
  
  <dt>Country</dt>
  <dd><input type="text" id="country" /></dd>
</dl>

<h2>Recurrence</h2>
<dl>
  <dt>Frequency</dt>
  <dd>
    <select id="frequency">
      <option value="1">Weekly</option>
      <option value="2">Monthly</option>
      <option value="3">Quarterly</option>
      <option value="4">Annually</option>
	  <option value="7">Every 4 weeks</option>
    </select>
  </dd>
  
  <dt>Start Date</dt>
  <dd><input type="text" id="start-date" /></dd>
  
  <dt>Day of Week</dt>
  <dd>
    <select id="day-of-week">
      <option value="0">Sunday</option>
      <option value="1">Monday</option>
      <option value="2">Tuesday</option>
      <option value="3">Wednesday</option>
      <option value="4">Thursday</option>
      <option value="5">Friday</option>
      <option value="6">Saturday</option>
    </select>
  </dd>
  
  <dt>Day of Month</dt>
  <dd>
    <select id="day-of-month">
      <option>1</option>
      <option>2</option>
      <option>3</option>
      <option>4</option>
      <option>5</option>
      <option>6</option>
      <option>7</option>
      <option>8</option>
      <option>9</option>
      <option>10</option>
      <option>11</option>
      <option>12</option>
      <option>13</option>
      <option>14</option>
      <option>15</option>
      <option>16</option>
      <option>17</option>
      <option>18</option>
      <option>19</option>
      <option>20</option>
      <option>21</option>
      <option>22</option>
      <option>23</option>
      <option>24</option>
      <option>25</option>
      <option>26</option>
      <option>27</option>
      <option>28</option>
      <option>29</option>
      <option>30</option>
      <option>31</option>
    </select>
  </dd>
</dl>

<p><button class="btn-donate">Donate</button></p>
// Let's be good developers and not pollute the global namespace
(function($) {
  
  // Let's make sure the DOM is ready
  $(function() {
    
    // Create an instance of the DonationService
    var ds = new BLACKBAUD.api.DonationService(
      $('.BBDonationApiContainer').data('partid')
    );
    
    // Create the donation object we'll send
    // In order to simplify our examples, some of this information is hard-coded.
    var donation = {
      MerchantAccountId: '00000000-0000-0000-0000-000000000000',
      Gift: {
        PaymentMethod: 0,
        Designations: [
          {
            Amount: 5.00,
            DesignationId: '00000000-0000-0000-0000-000000000000'
          }
        ]
      }
    };
    
    // Create our success handler
    var success = function(returnedDonation) {
      console.log(returnedDonation);
    };
    
    // Create our error handler
    var error = function(returnedErrors) {
      console.log('Error!');
    };
    
    // Attach our event listener to the donate button
    $('.btn-donate').click(function(e) {
      
      // Stop the button from submitting the form
      e.preventDefault(); 
      
      // Add the information our user has typed
      donation.Donor = {
        FirstName: $('#first-name').val(),
        LastName: $('#last-name').val(),
        Address: {
          StreetAddress: $('#address').val(),
          City: $('#city').val(),
          State: $('#state').val(),
          PostalCode: $('#zip').val(),
          Country: $('#country').val()
        }
      };
      
      // The following fields are always required
      donation.Gift.Recurrence = {
        Frequency: $('#frequency').val(),
        StartDate: $('#start-date').val()
      };
      
      // The remaining required values are different depending on what frequency the user selects
      var frequency = $('#frequency').val();
      switch (frequency) {
        case 1:
          donation.Gift.Recurrence.DayOfWeek = $('#day-of-week').val();
        break;
        case 2:
        case 3:
          donation.Gift.Recurrence.DayOfMonth = $('#day-of-month').val();
          // Purposefully letting selection fall through (no "break")
        case 4:
          donation.Gift.Recurrence.Month = $('#month').val();
        break;
		case 7:
		 donation.Gift.Recurrence.DayOfMonth=0;
		 donation.Gift.Recurrence.Month=0;
		 //Purposefully assigning DayOfWeek is -1 beacuse 0 is defined for Sunday.
		 donation.Gift.Recurrence.DayOfWeek =-1;
		break;
      };
        
      // Submit our donation
      ds.createDonation(donation, success, error);
    });
    
  });
}(jQuery));

Tribute Example

In this example, we're back to "proceeding directly to payment," as opposed to using the Payment 2.0 Part. This means we'll need to collect the donor information. I've also introduced the ability to add a tribute.

<h3>Donor Information</h3>
<dl>
  <dt>First Name</dt>
  <dd><input type="text" id="first-name" /></dd>
  
  <dt>Last Name</dt>
  <dd><input type="text" id="last-name" /></dd>
  
  <dt>Email</dt>
  <dd><input type="text" id="email" /></dd>
  
  <dt>Address</dt>
  <dd><textarea id="address"></textarea></dd>
  
  <dt>City</dt>
  <dd><input type="text" id="city" /></dd>
  
  <dt>State</dt>
  <dd><input type="text" id="state" /></dd>
  
  <dt>Zip</dt>
  <dd><input type="text" id="zip" /></dd>
  
  <dt>Country</dt>
  <dd><input type="text" id="country" /></dd>
</dl>

<h3>Tribute Information</h3>
<dl>
  <dt>First Name</dt>
  <dd><input type="text" id="tribute-first-name" /></dd>
  
  <dt>Last Name</dt>
  <dd><input type="text" id="tribute-last-name" /></dd>
  
  <dt>Description</dt>
  <dd><textarea id="tribute-description"></textarea></dd>
</dl>
      
<h3>Acknowledgee Information</h3>
<dl>
  <dt>First Name</dt>
  <dd><input type="text" id="acknowledgee-first-name" /></dd>
  
  <dt>Last Name</dt>
  <dd><input type="text" id="acknowledgee-last-name" /></dd>
  
  <dt>Email</dt>
  <dd><input type="text" id="acknowledgee-email" /></dd>
  
  <dt>Address</dt>
  <dd><textarea id="acknowledgee-address"></textarea></dd>
  
  <dt>City</dt>
  <dd><input type="text" id="acknowledgee-city" /></dd>
  
  <dt>State</dt>
  <dd><input type="text" id="acknowledgee-state" /></dd>
  
  <dt>Zip</dt>
  <dd><input type="text" id="acknowledgee-zip" /></dd>
  
  <dt>Country</dt>
  <dd><input type="text" id="acknowledgee-country" /></dd>
</dl>
      
<p><button class="btn-donate">Donate</button></p>
// Let's be good developers and not pollute the global namespace
(function($) {
  
  // Let's make sure the DOM is ready
  $(function() {
    
    // Create an instance of the DonationService
    var ds = new BLACKBAUD.api.DonationService(
      $('.BBDonationApiContainer').data('partid')
    );
    
    // Create the donation object we'll send
    // In order to simplify our examples, some of this information is hard-coded.
    var donation = {
      MerchantAccountId: '00000000-0000-0000-0000-000000000000',
      Tribute: {},
      Gift: {
        PaymentMethod: 0,
        Designations: [
          {
            Amount: 5.00,
            DesignationId: '00000000-0000-0000-0000-000000000000'
          }
        ]
      }
    };
    
    // Create our success handler
    var success = function(returnedDonation) {
      console.log(returnedDonation);
    };
    
    // Create our error handler
    var error = function(returnedErrors) {
      console.log('Error!');
    };
    
    // Attach our event listener to the donate button
    $('.btn-donate').click(function(e) {
      
      // Stop the button from submitting the form
      e.preventDefault(); 
      
      // Add the information our user has typed
      donation.Donor = {
        FirstName: $('#first-name').val(),
        LastName: $('#last-name').val(),
        Address: {
          StreetAddress: $('#address').val(),
          City: $('#city').val(),
          State: $('#state').val(),
          PostalCode: $('#zip').val(),
          Country: $('#country').val()
        }
      };

      // Add our tribute information
      // See REST api tech reference for more information on the Type field
      donation.Tribute.TributeDefintion = {
         Type: 'Tribute',
        Name: $('#tribute-first-name') + " " + $('#tribute-last-name'),     
        FirstName: $('#tribute-first-name'),
        LastName: $('#tribute-last-name'),
        Description: $('tribute-description')
      };
      
      // Add our acknowledgee information
      donation.Tribute.Acknowledgee = {
        FirstName: $('#acknowledgee-first-name').val(),
        LastName: $('#acknowledgee-last-name').val(),
        Address: {
          StreetAddress: $('#acknowledgee-address').val(),
          City: $('#acknowledgee-city').val(),
          State: $('#acknowledgee-state').val(),
          PostalCode: $('#acknowledgee-zip').val(),
          Country: $('#acknowledgee-country').val()
        }
      };
      
      // Submit our donation
      ds.createDonation(donation, success, error);
    });
    
  });
}(jQuery));


Using the Consent endpoints, you can quickly populate the available consents. This example uses jQuery to make an AJAX request. We also wrap this functionality in the Consent JavaScript Service, which is shown in this example.



Direct Debit Example

This feature can be used to configured the direct debit on ADF by using the payment's using the Donation endpoints.

Organizations have many donors (especially in international markets) that prefer to give gifts with Direct Debit (also known as ACH). To build parity with our current Advance Donation Form (ADF), we need to allow organizations to accept donations via direct debit on ADF. This functionality is wrapped under DirectDebit Service, as shown in the example.

<!--This div is use to show the direct debit section on a page-->
<div id="directDebitSection">
        <div class="formrow" id="tr_DDPDFInstructions">
            <div colspan="3">
                <span><i>In order to set up a Direct Debit instruction
                    online, you must be the account holder of a personal bank or building society account.
                    If you are not the only required signatory on your account or you would rather send
                    us a paper version please
                    <a ID="lnkDDPDF" title="Direct Debit PDF" href="DirectDebit.ddpdf"
                        Target="_blank" rel="noopener noreferrer">click here</a></i>
	            </span>
            </div>
        </div>
        <div class="formrow">
                <label ID="lblFinancialLBL">Financial Institution:</label>
                <input type="text" ID="txtFinancialInstitution" MaxLength="100"/>
        </div>
        <div class="formrow">
                <label ID="lblBranchName">Branch Name:</label>
                <input type="text" ID="txtBranchName" MaxLength="100"/>
        </div>
        <div class="formrow" id="tr_BankingSystemType">
                <label ID="lblBankingSystemType">Banking System Type:</label>
                <select ID="ddlBankingSystemType"></select>
        </div>
        <div class="formrow">
                <label ID="lblRoutNumLBL">Routing Number:</label>
                <input type="text" ID="txtRoutingNumber" MaxLength="9" />
               <!-- <asp:CustomValidator ID="cvRoutingNumber"  ClientValidationFunction="RoutingNumberClientValidation"  />   --> 
  
                <a ID="lnk_BankHelp" title="Display help details in another window" style="cursor:pointer;">
	<img src="images/help-32_1.gif" alt="help" title="Help" style="height:32px;width:36px;vertical-align:bottom; border:0;" />
                </a>
        </div>
        <div class="formrow" id="tr_CanadaTransitNum">
                <label ID="lblCanadaTransitNum">Transit Number:</label>
                <input type="text" ID="txtCanTransitNumber" MaxLength="5"/>
        </div>
        <div class="formrow">
                <label ID="lblAccountNumber">Account Number:</label>
                <span id="spn_AccountNo">
                    <input type="text" ID="txtAccountNumber" MaxLength="20"/>
                </span>
                <span id="spn_AccountNoNZ">
                    <input type="text" ID="txtAccountNumberNZ" Width="30" MaxLength="7"/>
					<span>-</span>
                    <input type="text" ID="txtSuffixNZ" Width="20" MaxLength="3" />
                    <label ID="lblSuffixNZ" Visible="false"></label>
                </span>
                    </div>
        <div class="formrow" id="tr_AccountType">
                <label ID="lblAccountType">Account Type:</label>
                <select ID="ddlAccountType"></select>
        
        </div>
        <div class="formrow">
                <label ID="lblAccountHolderName">Account Holder's Name:</label>
                <input type="text" ID="txtAccountHolder" MaxLength="50"/>
        </div>
        <div class="formrow" id="tr_CurrentDate" >
                <label ID="lblDebitDate">Date:</label>
                <label ID="lbl_CurrentDate"></label>
        </div>
        <div class="formrow" id="tr_OrigNumber">
                <label ID="lblOriginatorID">Service user's ID number:</label>
                <label ID="lbl_OrigNumber"></label>
        </div>
        <div id="tr_DDBankInstructions">
            <span colspan="3">
                <p>
                    <label><b>Instruction to your Bank or Building Society</b></label>
                </p>
                                   <label ID="lbl_DDBankInstructions">
<i>Please pay %1 Direct Debits from the account detailed in this Instruction subject to the safeguards assured by the Direct Debit Guarantee. I understand that this Instruction may remain with %1 and, if so, details will be passed electronically to my Bank/Building Society.</i>
					</label>						
                                
                    <label>
<i>Banks and Building Societies may not accept Direct Debit Instructions for some types of account.</i>
                    </label>
                
            </span>
        </div>
        <div id="tr_DDInstructions">
            <span colspan="3">
                <img src="images\dlogo.gif" alt="Direct Debit" title="Direct Debit" style="text-align: center;" />
                <a ID="lnk_DDGuarantee" title="Display the Direct Debit Guarantee in another window" style="cursor:pointer;color:blue;text-decoration:underline;">The Direct Debit Guarantee</a>
			</span>
        </div>
        <div id="tr_DDPDFInstructions2">
            <span colspan="2">
                <p>
                    <label>
<i>By clicking 'Donate Now' you are confirming that you are the account holder and that you are the only person required to authorise debits from this account.</i>
		</label>
                </p>
            </span>
        </div>
   </div>
// Let's be good developers and not pollute the global namespace
(function ($) {

 // Let's make sure the DOM is ready
$(function () {

  // Create an instance of the DonationService
  var ds = new BLACKBAUD.api.DonationService(
  $('.BBDonationApiContainer').data('partid'));
     
 
   //Create the donation object we'll send
  //In order to simplify our examples, some of this information is hard-coded.
  var donation = {
  MerchantAccountId: '00000000-0000-0000-0000-000000000000',
  BBSPReturnUri: window.location.href,
  BBSPTemplateSitePageId: 000,
  Gift: {
        PaymentMethod: 2,
        Designations: []
      }
  };

  // Create our success handler
  var success = function (returnedDonation) {
  console.log(returnedDonation);
  if (returnedDonation.Donation.Gift.PaymentMethod === 2) {
      window.location.href = window.location.href + "?t=" + d.Donation.Id;
  }
  };   

  // Create our error handler
  var error = function (returnedErrors) {
  console.log('Error!');
  };
  
	//Show and Hide directdebit div on the page
 function showHideDirectDebitDiv() {
   if ($("#paymentDirectDebit").prop("checked")) {
      $("#directDebitInformation").show();
      hideAndVisible_BankingTypeField();
      addCountryHandler();
     }
     else {
       $("#directDebitInformation").hide();
        }
    }

	//Call the function when we have to hide and visible the banking type field
    function hideAndVisible_BankingTypeField() {
        if ($('[id="ddlBankingSystemType"] option').length == 1) {
            $('#tr_BankingSystemType').css('display', 'none');
        } else {
            $('#tr_BankingSystemType').css('display', '');
        }
    }

	//Use to bind the banking types that is configured in CRM
    function bindDirectDebitData() {
        donationService.getBankingTypeData(function (d) {
            $.each(d, function () {
                $("#ddlBankingSystemType").append($("<option></option>").val(this["Abbreviation"]).text(this["Description"]));
            });
        });

        donationService.getAccountTypeData(function (d) {
            $.each(d, function () {
                $("#ddlAccountType").append($("<option></option>").val(this["Id"]).text(this["Description"]));
            });
        });

        donationService.getOriginIdAndTime(function (d) {
            $("#lbl_CurrentDate").text(d["Time"]);
            $("#lbl_OrigNumber").text(d["OriginId"]);
        });
    }

	//this function is used to select the banking type on the basis of country dropdown change
    function addCountryHandler() {
        var bankingSystemType = $('[id="ddlBankingSystemType"]'), addrCtl = $("[id='country'] :selected"), selectBankingOption, exists = false, bankingOptions;
        if (bankingSystemType && bankingSystemType.length > 0) {
            bankingOptions = $('[id="ddlBankingSystemType"] option');
            if (bankingOptions.length > 0) {
                if (!(bankingOptions.length === 1)) {
                    if (countryData && (validateCountry(addrCtl.val(), countryData.NZ) || validateCountry(addrCtl.val(), countryData.AUS))) {
                        selectBankingOption = "Aus_NZ";
                    }
                    else if (countryData && validateCountry(addrCtl.val(), countryData.UK)) {
                        selectBankingOption = "UK";
                    }
                    else if (countryData && validateCountry(addrCtl.val(), countryData.CAD) || validateCountry(addrCtl.val(), countryData.USA)) {
                        selectBankingOption = "USA";
                    }

                    exists = 0 !== bankingSystemType.find('option[value="' + selectBankingOption + '"]').length;
                    if (exists && exists === true) {
                        bankingSystemType.val(selectBankingOption);
                    } else {
                        bankingSystemType.val("Please Select");
                    }
                }
            }
            hideAndVisible_DirectDebitFields();
        }
    }

	//Hide and Visible direct debit fields on the basis of country dropdown and banking type dropdown change
    function hideAndVisible_DirectDebitFields() {
        var bankingType = "Please Select", htmlElement = "", routingNumberTextBoxLabel = "", selectedCountry = "", routingNumberTextBox = "", transitNumberBox = "",
            routingNumber = $('[id="txtRoutingNumber"]'),
            transitNumber = $('[id="txtCanTransitNumber"]'),
            routingNumberLabel = $('[id="lblRoutNumLBL"]'),
            addressCTL = $("[id='country'] :selected"),
            bankingSystemLabel = $('[id="lblBankingSystemType"]'),
            bankingSystemType = $('[id="ddlBankingSystemType"] :selected'),
            accountType = $('[id="tr_AccountType"],[id*="DC_AccountType"]'),
            accountNo = $('[id="spn_AccountNo"]'),
            accountNoNZ = $('[id="spn_AccountNoNZ"]'),
            financialInstitution = $('[id="lblFinancialLBL"]'),
            accountNoLabel = $('[id="lblAccountNumber"]'),
            routingNumberHelpSymbol = $('[id="lnk_BankHelp"]'),
            requiredFieldAccountType = $('[id="RequiredFieldAccountType"]'),
            ukFields = $('[id="tr_DDInstructions"], [id="tr_OrigNumber"], [id="tr_CurrentDate"], [id="tr_DDBankInstructions"], [id="tr_DDPDFInstructions"], [id="tr_DDPDFInstructions2"],[id="DC_DDInstructions"],[id="DC_OrigNumber"],[id="DC_CurrentDate"],[id="DC_DDBankInstructions"],[id="DC_DDPDFInstructions"],[id="DC_DDPDFInstructions2"]');

        if (!routingNumber || routingNumber.length <= 0) {
            return;
        }

        if (bankingSystemType && bankingSystemType.length > 0) {
            bankingType = bankingSystemType.attr("Value");
        }

        if (routingNumber && routingNumber.length > 0) {
            routingNumberTextBox = routingNumber;
        }

        if (addressCTL && addressCTL.length > 0) {
            selectedCountry = addressCTL.val();
        }

        if (routingNumberLabel && routingNumberLabel.length > 0) {
            routingNumberTextBoxLabel = routingNumberLabel;
        }

        if (transitNumber && transitNumber.length > 0) {
            transitNumberBox = transitNumber;
            $('[id="tr_CanadaTransitNum"]').css("display", "none");
        }
        accountNo.css("display", "");
        accountNoNZ.css("display", "");
        accountNoLabel.html("Account Number:");
        routingNumberHelpSymbol.css("display", "");
        if (ukFields && ukFields.length > 0) {

            ukFields.css('display', 'none');
        }

        if (countryData && validateCountry(selectedCountry, countryData.CAD) && transitNumberBox && transitNumberBox.length > 0 && bankingType === "USA") {
            routingNumberTextBoxLabel.html("Institution ID:");
            routingNumberTextBox.attr("maxlength", "4");
            routingNumberTextBox.val('');
            accountType.css("display", "none");
            accountNoNZ.css("display", "none");
            $('[id="tr_CanadaTransitNum"]').css("display", "");

        } else {
            if (bankingType !== "Please Select") {
                if (bankingType === "USA") {
                    routingNumberTextBoxLabel.html("Routing Number:");
                    routingNumberTextBox.attr("maxlength", "9");
                    routingNumberTextBox.val('');
                    accountType.css("display", "");
                    accountNoNZ.css("display", "none");
                }
                else if (bankingType === "UK") {
                    routingNumberTextBoxLabel.html("Sort Code:");
                    routingNumberTextBox.attr("maxlength", "6");
                    routingNumberTextBox.val('');
                    accountType.css("display", "none");
                    accountNoNZ.css("display", "none");
                    if (ukFields) {
                        ukFields.css('display', '');
                    }

                }
                else if (bankingType === "Europe") {
                    routingNumberTextBoxLabel.html("BIC:");
                    routingNumberTextBox.attr("maxlength", "11");
                    routingNumberTextBox.val('');
                    accountType.css("display", "");
                    accountNoNZ.css("display", "none");
                    routingNumberHelpSymbol.css("display", "none");
                }
                else if (bankingType === "Aus_NZ") {
                    routingNumberTextBoxLabel.html("BSB Number:");
                    routingNumberTextBox.attr("maxlength", "6");
                    routingNumberTextBox.val('');
                    accountType.css("display", "none");
                    accountNoNZ.css("display", "none");
                    if (countryData && validateCountry(selectedCountry, countryData.NZ)) {
                        accountNo.css("display", "none");
                        accountNoNZ.css("display", "");
                        routingNumberTextBoxLabel.html("Bank/Branch No.:");
                        accountNoLabel.html("Account No./Suffix:");
                        routingNumberTextBox.attr("maxlength", "7");
                        routingNumberTextBox.val('');
                    }
                }
                else if (bankingType === "Other") {
                    routingNumberTextBoxLabel.html("Bank Code:");
                    routingNumberTextBox.attr("maxlength", "25");
                    routingNumberTextBox.val('');
                    accountType.css("display", "");
                    accountNoNZ.css("display", "none");
                    routingNumberHelpSymbol.css("display", "none");
                }

                else {
                    routingNumberTextBoxLabel.html("Routing Number:");
                    routingNumberTextBox.attr("maxlength", "9");
                    routingNumberTextBox.val('');
                    accountType.css("display", "");
                    accountNoNZ.css("display", "none");

                }

            }
            else {
                routingNumberTextBoxLabel.html("Routing Number:");
                routingNumberTextBox.attr("maxlength", "9");
                accountType.css("display", "");
                accountNoNZ.css("display", "none");
            }
        }
    }

//this function is called when we click on help image of reoting number textbox(and it changes on the basis of banking type dropdown change)
    function donationBankHelp() {
        var sFeatures = 'WIDTH=392px,HEIGHT=400px,RESIZABLE=YES,SCROLLBARS=NO,TOOLBAR=NO,LEFT=5,TOP=20,location=No;status=No', oPopUp,
            bankingType = $('[id="ddlBankingSystemType"] :selected'), addressCTL = $("[id='country'] :selected"), selectedValue = "", selectedCountry = "", qParam = "";

        if (bankingType && bankingType.length > 0) {
            selectedValue = bankingType.attr("Value");;
        }
        if (addressCTL && addressCTL.length > 0) {
            selectedCountry = addressCTL.val();
        }


        if (countryData && validateCountry(selectedCountry, countryData.AUS) && selectedValue === 'Aus_NZ') {
            qParam = 'AUS';
        } else if (countryData && validateCountry(selectedCountry, countryData.NZ) && selectedValue === 'Aus_NZ') {
            qParam = 'NZ';
        } else if (countryData && validateCountry(selectedCountry, countryData.CAD) && selectedValue === 'USA' && $('[id="tr_CanadaTransitNum"]') && $('[id="tr_CanadaTransitNum"]').length > 0) {
            qParam = 'CAD';
        } else {
            switch (selectedValue) {
                case 'USA':
                    qParam = "USA";
                    break;
                case "Aus_NZ":
                    qParam = "AUS";
                    break;
                case "UK":
                    qParam = "UK";
                    break;
                default:
                    qParam = "USA";
                    break;
            }
        }

        oPopUp = new PopUpDialogBB('~/Admin/DonationHelp.ascx', '_blank', sFeatures, '&mode=2&displayfor=' + qParam);
        oPopUp.Show();
    }


    function dDGuarantee() {
        var sFeatures = 'WIDTH=650px,HEIGHT=415px,RESIZABLE=YES,SCROLLBARS=NO,TOOLBAR=NO,LEFT=5,TOP=20,location=No;status=No',
            oPopUp = new PopUpDialogBB('~/Admin/DonationHelp.ascx', '_blank', sFeatures, '&mode=3');
        oPopUp.Show();
    }

	//this is used to set country object with all possible value of the countries(like Abbreviation, Country Name, and Guid)
    function getCountryMappings() {

        //this is use for direct debit validations
        countryData = {};
        countryService.getCountries(function (d) {
            $.each(d, function () {
                var tmpData = {};
                tmpData.Id = this["Id"];
                tmpData.Abbreviation = this["Abbreviation"];
                tmpData.Description = this["Description"];
                switch (this["Id"].toUpperCase()) {
                    case 'D81CEF85-7569-4B2E-8F2E-F7CF998A3342':
                        countryData.USA = tmpData;
                        break;
                    case 'A2ECC209-3D20-4DDA-BC4C-7585C8E2E701':
                        countryData.UK = tmpData;
                        break;
                    case 'D9EE54CD-2183-490C-A3AD-11152B271335':
                        countryData.CAD = tmpData;
                        break;
                    case 'F189F24C-2538-46A1-8458-1E3F3967B843':
                        countryData.AUS = tmpData;
                        break;
                    case 'DA42443E-AB81-40EE-A239-91ED699C0801':
                        countryData.NZ = tmpData;
                        break;
                }

            });
        });
    }

	//for validate the country thatused to select the banking type on the basis of country dropdown change 
    function validateCountry(country, ctryData) {
        if (country.toUpperCase() === ctryData.Id.toUpperCase() || country.toUpperCase() === ctryData.Abbreviation.toUpperCase() || country.toUpperCase() === ctryData.Description.toUpperCase()) {
            return true;
        }
        return false;

    }
 
	 //Bind Direct Debit
	 
	    getCountryMappings();
        bindDirectDebitData();
		
		//Attach Listeners
		$("#recMonthly").click(function () {
        $("#directDebit").css("display", "");
        });
        $("#recOneTime").click(function () {
        $("#directDebit").css("display", "none");
        });
        $("#paymentDirectDebit").click(function () { showHideDirectDebitDiv(); })
        $("#ddlBankingSystemType").change(function () { hideAndVisible_DirectDebitFields(); })
$("#lnk_BankHelp").click(function () { donationBankHelp(); });
        $("#lnk_DDGuarantee").click(function () { dDGuarantee(); });

//Attach event listener on country change
$("#country").change(function () { addCountryHandler(); })
		
     // Attach our event listener to the donate button
   $('.btn-donate').click(function(e) {
      
      // Stop the button from submitting the form
      e.preventDefault(); 
	  
      //Payment Method(2) means direct debit and set all the properties of direct debit
        if (paymentMethod === "2" && $("#paymentDirectDebit").prop("checked")) {
            donation.Gift.DirectDebitInformation = {};
            var selectedCountry = $("#country :selected").val(), bankingType = $("#ddlBankingSystemType :selected").val();
            donation.Gift.DirectDebitInformation.FinancialInstitution = $("#txtFinancialInstitution").val();
            donation.Gift.DirectDebitInformation.BranchName = $("#txtBranchName").val();
            donation.Gift.DirectDebitInformation.AccountHolderName = $("#txtAccountHolder").val();
            donation.Gift.DirectDebitInformation.BankingType = bankingType;


            if (countryData && validateCountry(selectedCountry, countryData.CAD) && bankingType === "USA") {
                donation.Gift.DirectDebitInformation.RoutingNumber = $("#txtRoutingNumber").val();
                donation.Gift.DirectDebitInformation.TransitNumber = $("#txtCanTransitNumber").val();
            }
            else {
                donation.Gift.DirectDebitInformation.RoutingNumber = $("#txtRoutingNumber").val();
            }

            if (countryData && validateCountry(selectedCountry, countryData.NZ) && bankingType === "Aus_NZ") {
                donation.Gift.DirectDebitInformation.AccountNumber = $("#txtAccountNumberNZ").val();
                donation.Gift.DirectDebitInformation.SuffixNo = $("#txtSuffixNZ").val();
            }
            else {
                donation.Gift.DirectDebitInformation.AccountNumber = $("#txtAccountNumber").val();
            }

            if (bankingType === "Europe" || bankingType === "Other" || countryData && (!validateCountry(selectedCountry, countryData.CAD) && bankingType === "USA")) {
                donation.Gift.DirectDebitInformation.AccountType = $("#ddlAccountType :selected").val();
            }
            else {
                donation.Gift.DirectDebitInformation.AccountType = "";
            }

        }

     // Submitting the donation
     ds.createDonation(donation, success, error);
     }); 

  });
 }(jQuery));

Using Blackbaud Secure Payments

Integration with the Blackbaud Secure Payments service has been updated in the Advanced Donation Form.

<dl>
  <dt>First Name</dt>
  <dd><input type="text" id="first-name" /></dd>

  <dt>Last Name</dt>
  <dd><input type="text" id="last-name" /></dd>

  <dt>Email</dt>
  <dd><input type="text" id="email" /></dd>

  <dt>Address</dt>
  <dd><textarea id="address"></textarea></dd>

  <dt>City</dt>
  <dd><input type="text" id="city" /></dd>

  <dt>State</dt>
  <dd><input type="text" id="state" /></dd>

  <dt>Zip</dt>
  <dd><input type="text" id="zip" /></dd>

  <dt>Country</dt>
  <dd><input type="text" id="country" /></dd>
</dl>

<p><button class="btn-donate">Donate</button></p>
// Let's be good developers and not pollute the global namespace
(function($) {

// Let's make sure the DOM is ready
$(function() {

  // Create an instance of the DonationService
    var ds = new BLACKBAUD.api.DonationService(
      $('.BBDonationApiContainer').data('partid')
    );

  // Create the donation object we'll send
  // In order to simplify our examples, some of this information is hard-coded.
  var donation = {
    MerchantAccountId: '00000000-0000-0000-0000-000000000000',
    BBSPReturnUri: window.location.href,
    BBSPTemplateSitePageId: 000,
    Gift: {
      PaymentMethod: 0,
      Designations: [
        {
          Amount: 5.00,
          DesignationId: '00000000-0000-0000-0000-000000000000'
        }
      ]
    }
  };

  // Create our success handler
  var success = function(returnedDonation) {
    console.log(returnedDonation);
  };

  // Create our error handler
  var error = function(returnedErrors) {
    console.log('Error!');
  };

  // Attach our event listener to the donate button
  $('.btn-donate').click(function(e) {

    // Stop the button from submitting the form
    e.preventDefault(); 

    // Add the information our user has typed
    donation.Donor = {
      FirstName: $('#first-name').val(),
      LastName: $('#last-name').val(),
      Address: {
        StreetAddress: $('#address').val(),
        City: $('#city').val(),
        State: $('#state').val(),
        PostalCode: $('#zip').val(),
        Country: $('#country').val()
      }
    };

    // Submit our donation
    ds.createDonation(donation, success, error);
  });

});
}(jQuery));
// Let's be good developers and not pollute the global namespace
(function($) {

// Let's make sure the DOM is ready
$(function() {

  // Create an instance of the DonationService
    var ds = new BLACKBAUD.api.DonationService(
      $('.BBDonationApiContainer').data('partid')
    );

  // Create the donation object we'll send
  // In order to simplify our examples, some of this information is hard-coded.
  var donation = {
    MerchantAccountId: '00000000-0000-0000-0000-000000000000',
    BBSPReturnUri: window.location.href,
    BBSPTemplateSitePageId: 000,
    Gift: {
      PaymentMethod: 0,
      Designations: [
        {
          Amount: 5.00,
          DesignationId: '00000000-0000-0000-0000-000000000000'
        }
      ]
    }
  };

  // Create our success handler
  var success = function(returnedDonation) {
    console.log(returnedDonation);
  };

  // Create our error handler
  var error = function(returnedErrors) {
    console.log('Error!');
  };
  
  
  
  //set the public key by using public key service that is used to open the checkout pop up
    function GetPublicKey() {
    
    onPublicKeySuccess = function (reply) {
        publicKey = JSON.parse(reply.Data).PublicKey;
    };
   
	ds.getCheckoutPublicKey(onPublicKeySuccess, error);
	return publicKey;
    }
  
  
  //this is the function that calls the payment api to open the checkout pop up with all the parameters
    this.makePayment = function () {
        opened = false;
        var donor=donation.Donor;
        var checkout = new SecureCheckout(handleCheckoutComplete, handleCheckoutError, handleCheckoutCancelled, handleCheckoutLoaded);
        donationData = {
            "key": GetPublicKey(),
            'Amount': "5.00",
            'UseCaptcha': true,
            'BillingAddressCity': donor.Address.City,
            'BillingAddressCountry': donor.Address.Country,
            'BillingAddressLine': donor.Address.StreetAddress,
            'BillingAddressPostCode': donor.Address.PostalCode,
            'BillingAddressState': donor.Address.State,
            'BillingAddressEmail': donor.EmailAddress,
            'BillingAddressFirstName': donor.FirstName,
            'BillingAddressLastName': donor.LastName,
            'Cardholder': donor.FirstName + " " + donor.LastName,
            'ClientAppName': 'BBIS',
            'MerchantAccountId': donation.MerchantAccountId,
            'IsEmailRequired': true,
            'PrimaryColor': true,
            'SecondaryColor': true,
            'FontFamily': true,
            'IsNameVisible': true,
          'UseVisaCheckout':true,
          'UseMasterpass': true,
          'UseApplePay': true
        };

            return checkout.processCardNotPresent(donationData);
        }
  
  //when checkout popup is successfully loaded
    handleDonationCreated = function (data) {
        var orderID = JSON.parse(data.Data).OrderId;
    }


	function getUrlVars(url) {
      var vars = [], hash;
      var hashes = url.slice(url.indexOf('?') + 1).split('&');
      for (var i = 0; i < hashes.length; i++) {
        hash = hashes[i].split('=');
        vars.push(hash[0]);
        vars[hash[0]] = hash[1];
      }
        return vars;
    }
  
  //this function called when the checkout popup is loaded on a page
    function handleCheckoutLoaded() {

        if (!opened) {

            opened = true;
            var url = $("#bbCheckoutPaymentIframe").prop('src');
            var tid = getUrlVars(url)["t"];

            //save transaction id in global variable. Will be used throughout the transaction
            this.transactionIDl = tid;

            if (tid) {
                donation.TokenId = tid;
                ds.checkoutDonationCreate(donation, handleDonationCreated, error);
                return false;
            }
        }

        return false;
    }

	//when we cancel the payment pop up hen unbind all the binded events on checkout popup
    function UnBindPaymentCheckoutEvents() {
        $(document).unbind("checkoutComplete");
        $(document).unbind("checkoutLoaded");
        $(document).unbind("checkoutError");
        $(document).unbind("checkoutCancel");
    }

	//this is called when the payment is completed
    function handleCheckoutComplete(event, tranToken) {
        var Id=tranToken ? tranToken :(event?(event.detail?(event.detail.transactionToken?event.detail.transactionToken:null):null):null);
		
        if (Id) { 
            donation.TokenId = Id;
            ds.checkoutDonationComplete(donation, success, error);
        }
        else {
           console.log(error);
        }
		UnBindPaymentCheckoutEvents();
        return false;
    }

	//call when there is any error while doing the payment on checkout pop up
    handleCheckoutError = function (event, errorMsg, errorCode) {
        console.log(error);
    }

    //Cancel Donation if user close checkout popup
    function handleCheckoutCancelled() {
        try {
            ds.checkoutDonationCancel(donation, success, error);
        }
        catch (e) {
            //do not store this error. Already stored from server side
        }
        UnBindPaymentCheckoutEvents();
    }
  
  
	 //use this method for credit card payment through popup
    function ProcessCCPayment() {
        
            onValidationSuccess = function (result) {
            makePayment();
            return false;
        };
        onValidationFailed = function (error) {
            console.log(error);
        };

        ds.validateDonationRequest(donation, onValidationSuccess, onValidationFailed);

    }

  // Attach our event listener to the donate button
  $('.btn-donate').click(function(e) {

    // Stop the button from submitting the form
    e.preventDefault(); 

    // Add the information our user has typed
    donation.Donor = {
      FirstName: $('#first-name').val(),
      LastName: $('#last-name').val(),
      Address: {
        StreetAddress: $('#address').val(),
        City: $('#city').val(),
        State: $('#state').val(),
        PostalCode: $('#zip').val(),
        Country: $('#country').val()
      }
    };

    // Send the donation
	ProcessCCPayment()
  });

});
}(jQuery));

Styling + Error Handling + API Integration

This last example is meant to show a more realistic real-world example of the Advanced Donation Form API, including all the necessary error handling and styling. This example also incorporates the use of the CountryService, which is the javascript wrapper for the Country REST API endpoint.

Whereas all the other examples are designed to be inserted into an Advanced Donation Form Part, the complete example is designed to be completely standalone - even on a different server than the one serving your BBIS website.

Please note you'll need to update the references in the example below to your BBIS installation.

<!DOCTYPE html>
<html lang="en" ng-app="bbADF">
<head>
  
  <title>ADF - Complete Example</title>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css">
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
  <link rel="stylesheet" href="example-complete.css">
    
</head>
<body>
  
  <form class="form-horizontal" ng-controller="DonationController">
    <div class="container">
      <div class="row">
        <div class="col-sm-12">
          <h1>Advanced Donation Form <small>Complete Example</small></h1>
        </div>
      </div>
      <div class="row">
        <div class="col-sm-6">
          
          <h3>Donor Information</h3>
          
          <div class="form-group">
            <div class="col-sm-6">
              <input type="text" class="form-control" ng-model="Donor.Firstname" placeholder="Firstname" required>
            </div>
            <div class="col-sm-6">
              <input type="text" class="form-control" ng-model="Donor.Lastname" placeholder="Lastname" required>
            </div>
          </div>

          <div class="form-group">
            <div class="col-sm-12">
              <textarea class="form-control" placeholder="Address" ng-model="Donor.Address.StreetAddress"></textarea>
            </div>
          </div>
          
          <div class="form-group">
            <div class="col-sm-6">
              <select class="form-control" ng-model="Donor.Address.Country" ng-change="getStates()" ng-options="c.Description for c in countries track by c.Id" ng-change="getStates()" required>
                <option value="">Country</option>
              </select>
            </div>
            <div class="col-sm-6">
              <select class="form-control" ng-model="Donor.Address.State" ng-options="s.Description for s in states track by s.Id" required>
                <option value="">State</option>
              </select>
            </div>
          </div>

          <div class="form-group">
            <div class="col-sm-9">
              <input type="text" class="form-control" placeholder="City" ng-model="Donor.Address.City">
            </div>
            <div class="col-sm-3">
              <input type="text" class="form-control" placeholder="Zip" ng-model="Donor.Address.PostalCode" />
            </div>
          </div>

          <div class="form-group">
            <div class="col-sm-8">
              <input type="text" class="form-control" placeholder="Email" ng-model="Donor.EmailAddress" />
            </div>
            <div class="col-sm-4">
              <input type="text" class="form-control" placeholder="Phone" ng-model="Donor.Phone" />
            </div>
          </div>
          
          <div class="form-group">
            <div class="col-sm-4">
              <label class="btn btn-default" ng-model="Gift.IsCorporate" btn-checkbox>
                <i class="fa fa-fw" ng-class="{ 'fa-square-o': !Gift.IsCorporate, 'fa-check-square-o': Gift.IsCorporate }"></i> Corporate?
              </label>
            </div>
            <div class="col-sm-8" ng-show="Gift.IsCorporate">
              <input type="text" class="form-control" ng-model="Donor.OrganizationName" placeholder="Organization Name" required>
            </div>
          </div>
          
          <div class="form-group">
            <div class="col-sm-4">
              <label class="btn btn-default" ng-model="Gift.isAnonymous" btn-checkbox>
                <i class="fa fa-fw" ng-class="{ 'fa-square-o': !Gift.isAnonymous, 'fa-check-square-o': Gift.isAnonymous }"></i> Anonymous?
              </label>
            </div>
          </div>
          
        </div>
        <div class="col-sm-6">
        
          <h3>Gift Information</h3>
          
          <div class="form-group">
            <div class="col-sm-6">
              <div class="btn-group">
                <label class="btn btn-default" ng-repeat="option in amounts" ng-model="defaults.amount" btn-radio="option.amount" required>
                  <span ng-bind="option.label"></span>
                </label>
              </div>
            </div>
            <div class="col-sm-6">
              <div class="btn-group">
                <label class="btn btn-default" ng-repeat="option in payments" ng-model="defaults.payments" btn-radio="option.id" required>
                  <span ng-bind="option.label"></span>
                </label>
              </div>
            </div>
          </div>
          
          <div class="form-group" ng-show="defaults.amount == 'other'">
            <div class="col-sm-12">
              <div class="input-group">
                <div class="input-group-addon">$</div>
                <input type="text" class="form-control" ng-model="Gift.Amount" placeholder="Other Amount" ng-required="Gift.SelectedAmount == 'other'">
              </div>
            </div>
          </div>
          
          <div class="form-group">
            <div class="col-sm-12">
              <textarea class="form-control" ng-model="Gift.Comments" placeholder="Comments"></textarea>
            </div>
          </div>
          
          <div class="form-group">
            <div class="col-sm-6">
              <select class="form-control" ng-model="defaults.designation" ng-options="designation.label for designation in designations track by designation.id" required>
                <option value="">Designation</option>
              </select>
            </div>
            <div class="col-sm-6">
              <div class="btn-group">
                <label class="btn btn-default" ng-repeat="option in types" ng-model="defaults.type" btn-radio="option.id">
                  <span ng-bind="option.label"></span>
                </label>
              </div>
            </div>
          </div>
          
          <div ng-show="defaults.type == 'recurring'">

            <div class="form-group">
              <div class="col-sm-6">
                <div class="input-group">
                  <input type="text" class="form-control" ng-model="Gift.Recurrence.StartDate" datepicker-popup="MMMM dd, yyyy" is-open="openedStartDate" show-button-bar="false" min-date="minDate" placeholder="Start Date" required />
                  <span class="input-group-btn">
                    <button type="button" class="btn btn-default" ng-click="open($event, 'openedStartDate')">
                      <i class="fa fa-calendar"></i>
                    </button>
                  </span>
                </div>
              </div>
              <div class="col-sm-6">
                <div class="input-group">
                  <input type="text" class="form-control" ng-model="Gift.Recurrence.EndDate" datepicker-popup="MMMM dd, yyyy" is-open="openedEndDate" show-button-bar="false" min-date="minDate" placeholder="End Date" />
                  <span class="input-group-btn">
                    <button type="button" class="btn btn-default" ng-click="open($event, 'openedEndDate')">
                      <i class="fa fa-calendar"></i>
                    </button>
                  </span>
                </div>
              </div>
            </div>
            
            <div class="form-group">
              <div class="col-sm-4">
                <select class="form-control" ng-model="Gift.Recurrence.Frequency" required>
                  <option value="">Frequency</option>
                  <option value="1">Weekly</option>
                  <option value="2">Monthly</option>
                  <option value="3">Quarterly</option>
                  <option value="4">Annually</option>
				  <option value="7">Every 4 weeks</option>
                </select>
              </div>
              <div ng-show="Gift.Recurrence.Frequency">
                <div class="col-sm-4" ng-show="Gift.Recurrence.Frequency == 1">
                  <select class="form-control" ng-model="Gift.Recurrence.Month" required>
                    <option value="">Month</option>
                    <option value="1">January</option>
                    <option value="2">February</option>
                    <option value="3">March</option>
                    <option value="4">April</option>
                    <option value="5">May</option>
                    <option value="6">June</option>
                    <option value="7">July</option>
                    <option value="8">August</option>
                    <option value="9">September</option>
                    <option value="10">October</option>
                    <option value="11">November</option>
                    <option value="12">December</option>
                  </select>
                </div>
                <div class="col-sm-4" ng-show="Gift.Recurrence.Frequency == 1">
                  <select class="form-control" ng-model="Gift.Recurrence.DayOfWeek" required>
                    <option value="">Day of Week</option>
                    <option value="0">Sunday</option>
                    <option value="1">Monday</option>
                    <option value="2">Tuesday</option>
                    <option value="3">Wednesday</option>
                    <option value="4">Thursday</option>
                    <option value="5">Friday</option>
                    <option value="6">Saturday</option>
                  </select>
                </div>
                <div class="col-sm-4" ng-show="Gift.Recurrence.Frequency != 1">
                  <select class="form-control" ng-model="Gift.Reccurence.DayOfMonth" required>
                    <option value="">Day of Month</option>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                    <option value="4">4</option>
                    <option value="5">5</option>
                    <option value="6">6</option>
                    <option value="7">7</option>
                    <option value="8">8</option>
                    <option value="9">9</option>
                    <option value="10">10</option>
                    <option value="11">11</option>
                    <option value="12">12</option>
                    <option value="13">13</option>
                    <option value="14">14</option>
                    <option value="15">15</option>
                    <option value="16">16</option>
                    <option value="17">17</option>
                    <option value="18">18</option>
                    <option value="19">19</option>
                    <option value="20">20</option>
                    <option value="21">21</option>
                    <option value="22">22</option>
                    <option value="23">23</option>
                    <option value="24">24</option>
                    <option value="25">25</option>
                    <option value="26">26</option>
                    <option value="27">27</option>
                    <option value="28">28</option>
                    <option value="29">29</option>
                    <option value="30">30</option>
                    <option value="31">31</option>
                  </select>
                </div>
              </div>
            </div>

          </div>
        </div>
      </div>
      <div class="row">
        <div class="col-sm-6">

          <div class="form-group">
            <div class="col-sm-12">
              
            </div>
          </div>
        </div>
        <div class="col-sm-6">
          
        </div>
      </div>
      <div class="row">
        <div class="col-sm-12">
          <p>
            <button class="btn btn-lg btn-primary btn-donate" ng-click="log()">
              <i class="fa fa-lock"></i> Donate
            </button>
          </p>
        </div>
      </div>
    </div>
  
  </form>
  
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.11.2/ui-bootstrap-tpls.min.js"></script>
  <script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
  <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>  
  <script src="//chs6bobbyear02.blackbaud.global/Client/Scripts/easyXDM/easyXDM.min.js"></script>
  <script src="//chs6bobbyear02.blackbaud.global/Client/Scripts/API/BBAPI-min.js"></script>
  <script src="example-complete.js"></script>
  
</body>
</html>
'use strict';

// Create our Angular application
angular.module('bbADF', ['ui.bootstrap'])
.controller('DonationController', function($scope, CountryService) {

  // Controls the available donor types
  $scope.defaults = {
    type: '', // single | recurring
    payments: '', // credit | later
    amount: 0 // dollar amount | other
  };

  $scope.types = [
    {
      id: 'single',
      label: 'Single Gift'
    },
    {
      id: 'recurring',
      label: 'Recurring Gift'
    }
  ];

  $scope.payments = [
    {
      id: 'credit',
      label: 'Credit Card'
    },
    {
      id: 'later',
      label: 'Bill Me Later'
    }
  ];

  $scope.amounts = [
    {
      amount: 5,
      label: '$5'
    },
    {
      amount: 10,
      label: '$10'
    },
    {
      amount: 25,
      label: '$25'
    },
    {
      amount: 'other',
      label: 'Other'
    }
  ];

  $scope.designations = [
    {
      id: '0001',
      label: 'Designation 1'
    },
    {
      id: '0002',
      label: 'Designation 2'
    }
  ];

  // Calendar manipulation
  $scope.minDate = new Date();
  $scope.open = function($event, opened) {
    $event.preventDefault();
    $event.stopPropagation();
    $scope[opened] = true;
  };

  // Temporarily debugging
  $scope.log = function() {
    console.log(this);
  };
  
  // Request the states for a particular country
  $scope.getStates = function() {
    CountryService.getStates($scope.Donor.Address.Country.Id).success(function(data) {
      $scope.states = data;
    }).error(function() {
      alert('Error loading states.');
    });
  }

  CountryService.getCountries().success(function(data) {
    $scope.countries = data;
  }).error(function() {
    alert('Error loading countries.');
  });

})
.service('CountryService', function($http) {
  
  // Baseurl when using the Advanced Donation Form API
  var baseurl = 'http://chs6bobbyear02.blackbaud.global/Webapi/';

  // Request countries
  this.getCountries = function() {
    return $http.get(baseurl + 'Country');
  }

  // Request states when a country is selected
  this.getStates = function(id) {
    return $http.get(baseurl + 'Country/' + id + '/State');
  };

});
/* Currently only using Bootstrap styles */

Advanced Donation Form Generator

Overview:

The ADF form generator is a custom content part to be used as an internal tool to generate a barebones ADF template HTML document that developers can use as a starting point for their ADF work. The workflow for using the generator is outlined below.

  1. Create a new custom content part using the Administration menu in BBIS.
  2. Copy and paste the "Editor" and "Web page display" HTML code available on Github.
  3. In the initialize javascript function field, put "init_form" as the function name.
  4. Fill out the name and description to your liking.
  5. Save the content part.
  6. Create a new page from Site Explorer. It should be hidden from the public facing site, as it will only be used to host the generator tool for internal access.
  7. On the newly created internal page, insert the custom content part created above. Use the edit feature to fill in the options you would like your form to have/not have. Remember to populat your designations list.
  8. Select save and the form will be updated with your selections
  9. Select "View This Page" in the top left corner of the BBIS site, and then click the "Get HTML" button on the donation form. A modal will appear from which you can copy the code for your own ADF.
  10. Paste the code into your favorite text editor. There are some "TODO" tags throughout the code that you must act on prior to the ADF going live. Most just require you to delete leftover code from the generator. Use your editor's "find" feature (Ctrl + F) to find all strings matching "TODO" to make sure you see them all.
  11. Uncomment and fill out the data in the first javascript function. Follow the example format to ensure it works correctly. GUID's can be found using the special selectors or querying the appropriate database tables.
  12. Copy and paste the completed code to an ADF part. You now have a basic, fully functioning, donation form up and running.

Known Issues:

  • Tributes need tribute definition details / types in order for them to work correctly. This was not implemented in the wizard. In order for tributes to function correctly, you will need to populate the relevant properties yourself. See the ADF "Create Donation" API for more information.
  • Inputted details such as merchant account ID and BBSPReturnUri do not carry over to the form options. Instead, manually enter the information as outlined in step 11.

The entirety of this code is publicly available on Github. Community input and pull requests are welcome and appreciated.