Saving an html form to a table? - javascript

Issue: I want a way to verify if a user has already connected their bank account. What i have isn't saving to the table so i have no way to verify it from the db.
I want: I want to only save a stripe_account_id to the bankaccount table (which is a column) some way through the forms submit. Have it be unique and allowed to be overridden
This is what I have done so far:
Bank Account Controller:
def new
unless current_user.stripe_token
redirect_to new_user_stripe_account_path and return
end
begin
#stripe_account = Stripe::Account.retrieve(current_user.stripe_token)
#bank_account = BankAccount.new
#stripe_account = StripeAccount.find(params[:stripe_account_id])
rescue Stripe::StripeError => e
handle_error(e.message, 'new')
rescue => e
flash[:error] = e.message
end
end
def create
unless params[:token] && current_user.stripe_token
redirect_to new_bank_account_path and return
end
begin
token = params[:token]
stripe_account = Stripe::Account.retrieve(current_user.stripe_token)
stripe_account.external_account = params[:token]
stripe_account.save
flash[:success] = "Your bank account has been added!"
redirect_to dashboard_path
#bank_account = BankAccount.new(bank_account_params)
#bank_account.save!
rescue Stripe::StripeError => e
flash[:error] = e.message
rescue => e
flash[:error] = e.message
end
end
private
def set_bank_account
#bank_account = BankAccount.find(params[:id])
end
def bank_account_params
params.require(:bank_account).permit()
end
end
Routes:
resources :users do
resources :stripe_accounts
end
resources :stripe_accounts do
resources :bank_accounts
end
resources :bank_accounts
Without having the resources by itself, i get an error: "no post /bank_accounts" --- before i realized i had no way to verify a user having a bankaccount connected, it wasn't nested
Here's the gist of the form:
<form action="/bank_accounts" method="POST" id="payment-form-1">
<input type="hidden" name="token" />
<label for="country">Country</label>
<select id="country" class="form-control">
<option value="US">United States</option>
<option value="ES">Spain</option>
</select>
<label for="currency">Currency</label>
<select id="currency" class="form-control">
<option value="EUR">Euro</option>
</select>
<label for="routing-number">Routing Number</label>
<input type="text" class="form-control" id="routing-number" value="110000000" />
<label for="account-number">Account Number</label>
<input type="text" class="form-control" id="account-number" value="000123456789" />
<label for="account-holder-name">Account Holder Name</label>
<input type="text" class="form-control" id="account-holder-name" />
<label for="account-holder-type">Account Holder Type</label>
<select id="account-holder-type" class="form-control">
<option value="individual">Individual</option>
<option value="company">Company</option>
</select>
<%= hidden_field_tag :authenticity_token, form_authenticity_token -%>
<%= hidden_field_tag :stripeToken, current_user.stripe_token -%>
<%= hidden_field_tag :stripe_account_id, :value => #stripe_account_id %>
<button type="submit">Submit</button>
<div class="outcome">
<div class="error"></div>
<div class="success">
Success! Your Stripe token is <span class="token"></span>
</div>
</div>
</form>
The form is then sent using javascript:
<script>
var stripe = Stripe('pk_test_W1234567qTSqQJucPWU8kh');
function setOutcome(result) {
var successElement = document.querySelector('.success');
var errorElement = document.querySelector('.error');
successElement.classList.remove('visible');
errorElement.classList.remove('visible');
if (result.token) {
// In this example, we're simply displaying the token
successElement.querySelector('.token').textContent = result.token.id;
successElement.classList.add('visible');
// In a real integration, you'd submit the form with the token to your backend server
var form = document.querySelector('form');
form.querySelector('input[name="token"]').setAttribute('value', result.token.id);
form.submit();
} else {
errorElement.textContent = result.error.message;
errorElement.classList.add('visible');
}
}
document.querySelector('form').addEventListener('submit', function(e) {
e.preventDefault();
var bankAccountParams = {
country: document.getElementById('country').value,
currency: document.getElementById('currency').value,
account_number: document.getElementById('account-number').value,
account_holder_name: document.getElementById('account-holder-name').value,
account_holder_type: document.getElementById('account-holder-type').value,
}
if (document.getElementById('routing-number').value != '') {
bankAccountParams['routing_number'] = document.getElementById('routing-number').value;
}
stripe.createToken('bank_account', bankAccountParams).then(setOutcome);
});
</script>
Ultimately, I am simply wanting to save a reference to the bankaccount table so i know if an end user has filled out their bank account data yet and for view purposes to remind them they have already.
I would like to save to the bankaccount table the stripe_account.id (this is associated with a user in the stripeaccount table), this way ill know which users have already filled this out. (the bankaccount table has a stripe_account_id column, id, created_at, and updated_at).
Is there way to do this from the html form, from the javascript, etc.? Is my controller just wrong?

To save the external accounts ids to the database, you would need to do customer.sources.all(object: "bank_account"), then get the id of each and save it to the associated StripeAccount (I guess) associated to the user (while making sure you are duplicating ids).
https://stripe.com/docs/api/customer_bank_accounts/list
Personally I think you don't need to store the bank account ids in your database, you can just fetch it from Stripe when you need it.

Related

How can I keep old value selected option on edit request in VueJS 2?

I have some records with relationships on db. I fetch them on laravel backend like this
$teams = Team::with('skills')->find($id);
return response()->json([
'teams' =>$teams,
], Response::HTTP_OK);
and on front i am using vue js to edit team record
editTeam(id) {
axios.get('/teams/'+id+'/edit')
.then(response => {
// console.log(response)
this.id = response.data.teams.id,
this.edit_team_name = response.data.teams.team_name
...//some other data
this.edit_team_skills = response.data.teams.skills (//i want to pass here response.data.teams.skills.skills_name but it does not work)
})
},
and edit modal
<div class="form-group">
<label class="form-label" for="team_name">Team Name</label>
<input v-model="edit_team_name" id="team_name" type="text" class="form-control" >
</div>
<div class="form-group">
<label class="form-label select-label" for="team_foreman">Team Skill</label>
<select v-model="edit_team_skills" class="form-select" id="team_foreman" >
<option v-for="skill in skills" :value="skill.id" :key="skill.id">{{skill.skills_name}}</option>
</select>
</div>
So when i click edit button i get team_name on v-model="edit_team_name" but i dont know how to keep selected also old value for v-model="edit_team_skills"

how to display api errors in javascript

I am working with stripe, using the code found on their page to create a new account. Everything works fine, however when someone inserts wrong data in a field and we press on submit nothing happens and I can see in the console:
{
"error": {
"message": "This value must be greater than 1900 (it currently is '1670').",
"param": "account[individual][dob][year]",
"type": "invalid_request_error"
}
this being the response of the api (I tried to enter 1670 in the date of birth).
how can I display this on the page for the user?
here is my html code for the page:
<form class="my-form" method="post" role="form">
{% csrf_token %}
<input type="hidden" name="token" id="token">
<label>
<span>First Name</span>
<input class="inp-first-name" name="first_name" required>
</label>
<label>
<span>Last Name</span>
<input class="inp-last-name" name="last_name" required>
</label>
<label>
<span>dob year</span>
<input class="inp-dob-year" name="dob_year" required>
</label>
<label>
<span>dob month</span>
<input class="inp-dob-month" name="dob_month" required>
</label>
<label>
<span>dob day</span>
<input class="inp-dob-day" name="dob_day" required>
</label>
<fieldset>
<legend>Address</legend>
<label>
<span>Street Address Line 1</span>
<input class="inp-street-address1" name="street_address1" required>
</label>
<label>
<span>Street Address Line 2</span>
<input class="inp-street-address2" name="street_address2">
</label>
<label>
<span>City</span>
<input class="inp-city" name="city" required>
</label>
<label>
<span>State</span>
<input class="inp-state" name="state" required>
</label>
<label>
<span>Postal Code</span>
<input class="inp-zip" name="zip" required>
</label>
{{ form }}
</fieldset>
<button type="submit">Submit</button>
</form>
</table>
{% endblock %}
{% block body_scripts %}
<script>
const stripe = Stripekey
const myForm = document.querySelector('.my-form');
myForm.addEventListener('submit', handleForm);
async function handleForm(event) {
event.preventDefault();
const result = await stripe.createToken('account', {
legal_entity: {
type:'individual',
first_name: document.querySelector('.inp-first-name').value,
last_name: document.querySelector('.inp-last-name').value,
dob:{
year: parseInt(document.querySelector('.inp-dob-year').value),
month: parseInt(document.querySelector('.inp-dob-month').value),
day: parseInt(document.querySelector('.inp-dob-day').value),
},
address: {
line1: document.querySelector('.inp-street-address1').value,
line2: document.querySelector('.inp-street-address2').value,
city: document.querySelector('.inp-city').value,
state: document.querySelector('.inp-state').value,
postal_code: document.querySelector('.inp-zip').value,
},
},
tos_shown_and_accepted: true,
});
if (result.token) {
document.querySelector('#token').value = result.token.id;
myForm.submit();
}
}
</script>
I am building a website with python, so my knowledge with javascript is limited. Any help would be appreciated.
You can achieve this by adding a new HTML element to contain error messages and setting the innerText to the error message.
I added a div with an id of stripe-errors
if (result.token) {
document.querySelector('#token').value = result.token.id;
myForm.submit();
} else if (result.error) {
let stripeErrors = document.getElementById('stripe-errors');
stripeErrors.innerText = result.error.message;
}
The limitation of that is that you only have one place to display the error messages and the error messages don't explicitly say what field they're referencing, although within context it is probably clear enough. To be crystal clear you could use the error.param to map account[individual][dob][year] to the .inp-dob-year input field or to another element to display the error message.
This would look something like:
if (result.token) {
document.querySelector('#token').value = result.token.id;
myForm.submit();
} else if (result.error) {
// create an object as a map from the error.param to the elements that should be used to display error messages
const errorTypeFieldMap = {
'account[individual][dob][year]': '.inp-dob-year-error'
}
let errorElementSelector = errorTypeFieldMap[result.error.param];
if (errorElementSelector !== undefined) {
let errorElement = document.querySelector(errorElementSelector);
errorElement.innerText = result.error.message;
} else {
// display a generic error?
}
}
You should get the error(create a variable for the error json and parse it for the exact response you want) in the same function as you did the request and then get the element of the element you want to show the error message and asign the value of the response you want to show. You could use some
var x = document.getElementById(variable);
x.value = variable with the error;
}

Trouble creating Stripe Token: 402 (Payment Required) error

Good day everyone,
Below is the error code that is thrown in console:
(index):3 POST https://api.stripe.com/v1/tokens 402 (Payment Required)
(index):3 POST https://api.stripe.com/v1/tokens 402 (Payment Required)c # (index):3e # (index):3a # (index):3Stripe.isDoubleLoaded.Stripe.xhr # (index):3Stripe.a._rawRequest # (index):2Stripe.a.request # (index):2Stripe.token.a.create # (index):2Stripe.card.b.createToken # (index):2Stripe.a._channelListener # (index):2incoming # (index):2f # (index):2
Below is the javascript code
// Generate the user token
$(function() {
// Once the user has submited the form
$(".submit").click(function(e) {
// Prevent the form from submiting by default
e.preventDefault();
// Ensure that checkbox is checked
if($('#checkbox').is(":checked")) {
// Prevent the form from submiting by default
var $form = $('#payment-form');
// Request a token from Stripe:
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from being submitted:
return false;
}
else {
// Display an error message to the user by writting directly into the header error tag
document.getElementById('checkboxError').innerHTML = "You must kindly accept the terms and conditions to continue.";
}
});
// Ensure that checkbox is checked
if($('#checkbox').is(":checked")) {
var appendedStripeToken = false;
function stripeResponseHandler(status, response) {
// Grab the form:
var $form = $('#payment-form');
if (response.error) { // Problem!
// Scroll to the billing section
$("#billingError").scrollTop();
// Show the errors on the form:
$form.find('.payment-errors').text(response.error.message);
$form.find('.submit').prop('disabled', false); // Re-enable submission
} else { // Token was created!
// Get the token ID:
var token = response.id;
handleCall(token);
}
// What to do after the token has been generated.
function handleCall(token) {
var $form = $('#payment-form');
if (!appendedStripeToken) {
// Insert the token into the form so it gets submitted to the server
appendedStripeToken = true;
phpCall();
}
}
// Post the package name, the token, and the user name information to the billing.php page
function phpCall() {
if( appendedStripeToken === true ){
$.ajax({
type: "POST",
data: {run: true, packageName: $('#packageName').val(), token: token, userName: $('#userName').val(),customerName: $('#customerName').val() },
url: '/app/functions/billing.php',
success: function (response) {//response is value returned from php (for your example it's "bye bye"
$('#payment-form').prop('disabled', true); // TODO: give your html-submit-input-tag an "id" attribute
window.location = response;
}
});
}
}
}
}
});
Below is the HTML code
<!-- Package name to be submitted to server -->
<input type="hidden" id="packageName" value="{{ packageName|capitalize }}">
<!-- Username to be submitted to server -->
<input type="hidden" id="userName" value="{{ userName }}">
<input type="hidden" id="customerName" value="{{ customerName }}">
<div class="form-row">
<label for="cardHolder">Cardholder Name</label><br>
<input type="text" id="cardHolder" size="20" data-stripe="name">
</label>
</div>
<br><br>
<div class="form-row">
<label for="cardNumber">Card Number </label><br>
<input type="text" id="cardNumber" size="20" data-stripe="number">
</label>
</div>
<br>
<img src="/public/images/credit-card/visa.png" class="card-visa">
<img src="/public/images/credit-card/mastercard.png" class="card-mastercard">
<img src="/public/images/credit-card/american-express.png" class="card-aexpress">
<br>
<div class="form-row">
<label for="cardExpiration"> Expiration (MM/YY)</label><br>
<input class="expirationNumber" type="text" size="2" id="cardExpiration" data-stripe="exp_month">
</label>
<span> / </span>
<input class="expirationNumber" type="text" size="2" data-stripe="exp_year">
</div>
<br><br>
<div class="form-row">
<label for="cardCVC">CVC</label><br>
<input type="text" id="cardCVC" size="4" data-stripe="cvc">
</label>
</div>
</div>
</div>
<input type="checkbox" id="checkbox">
<label for="checkbox">By purchasing this package you are agreeing to our Terms & Conditions</label><br><br>
<h4 id="checkboxError"></h4>
<button type="submit" class="submit btn-tangerine">Submit Payment</button>
</form>
Any help would be greatly appreciated!
I thnk that the main error lies in the following line:
Stripe.card.createToken($form, stripeResponseHandler);
What is suppose to happen is really simple. Token gets created when all proper information are given, and then the token along with other information are posted via ajax to the server where a PHP code will create the charge using these information.
I was facing same issue when I add test API KEYS for payment, then site was working fine and when I add live key then site shows same error on console.
But problem was, I was testing live key with test credit card number. May be you were doing same mistake
And sorry for bad English.

Stripe::InvalidRequestError (This customer has no attached payment source)

There seems to be a problem with sending customer data and token back to Stripe's server. I'm currently using the test api to make dummy transactions. But, I cannot get past this point for no reason at all. I've tried everything to fix this error. I will post the code and error message below.
Subscriptions_Controller.rb
class SubscriptionsController < ApplicationController
before_filter :authenticate_user!, except: [:new]
before_action :redirect_to_signup, only: [:new]
def show
end
def new
#subscription = current_user.subscription
if #subscription.active
#stripe_customer = Stripe::Customer.retrieve(#subscription.stripe_user_id)
#stripe_subscription = #stripe_customer.subscription.first
end
end
def create
token = params[:stripeToken]
customer = Stripe::Customer.create(
:source => token,
:plan => "gbsubscriptionlevel1",
:email => current_user.email
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_subscription_path
current_user.subscription.stripe_user_id = customer.id
current_user.subscription.active = true
current_user.subscription.save
redirect_to users_index_path
end
def cancel_subscription
#stripe_customer = Stripe::Customer.retrieve(
current_user.subscription.stripe_user_id
)
#stripe_subscription = #stripe_customer.subscription.first
end
private
def redirect_to_signup
if !user_signed_in?
session["user_return_to"] = new_subscription_path
redirect_to new_user_registration_path
end
end
end
_stripe_form.html.erb
<div class="container">
<%= form_tag subscription_path, id: 'payment-form' do %>
<form action="/subscription" method="POST" id="payment-form">
<span class="payment-errors"></span>
<div class="row">
<div class="col-xs-4">
<label>
<span>Card Number</span>
<input value="4242 4242 4242 4242" class="form-control" type="text" size="20" data-stripe="number"/>
</label>
</div>
</div>
<div class="row">
<div class="col-xs-1">
<label>
<span>CVC</span>
<input value="123" class="form-control" type="text" size="4" data-stripe="cvc"/>
</label>
</div>
</div>
<div class="row">
<div class="col-xs-1">
<label>MM</label>
<input value="12" class="form-control" type="text" size="2" data-stripe="exp-month" placeholder="01"/>
</div>
<div class="col-xs-1">
<label>YYYY</label>
<input value="2019" class="form-control" type="text" size="3" data-stripe="exp-year" placeholder="2020"/>
</div>
</div>
<div class="row">
<div class="col-xs-1">
<br/>
<button class="btn btn-primary-outline" type="submit">Create Subscription</button>
</div>
</div>
</form>
<% end %>
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
</div>
subscription.js
Stripe.setPublishableKey('pk_test_tmBNNUvHTmtWXLhSL1q647iH');
function stripeResponseHandler(status, response) {
var $form = $('#payment-form');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false);
} else {
// response contains id and card, which contains additional card details
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// and submit
$form.get(0).submit();
}
}
jQuery(function ($) {
$('#payment-form').submit(function (event) {
var $form = $(this);
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
});
stripe.rb
Stripe.api_key = ENV["STRIPE_API_TEST_SECRET_KEY"]
That response typically arises after you try to attach a Subscription to someone with no card token attached. From your code, I'd hazard a guess that you're running into a CardError and then despite that, trying to attach a Subscription anyway, which will not work.

Apache Cordova connecting to Asp.net Web Application in MVC5

I currently have a an ASP.NET Web Application using MVC 5 with asp.net-identify and user roles enabled.
The site is working well and handling data requests to our database tables and blob storage.
We have a mobile app written in Apache Cordova Visual Studio 2015 which implements Bluetooth LE all working as expected.
I have learnt a huge amount to get to just this stage, but now I have hit a brick wall and appreciate some solid advice/guidance.
I'm am trying to initially log my users in to the web site from my Mobile App automatically and re-direct them to a specific page.
My MVC site code for logging in is below.
//
// GET: /Account/AppLogin
[AllowAnonymous]
public ActionResult AppLogin()
{
ViewBag.ReturnUrl = "not used";
return View();
}
//
// POST: /Account/AppLogin
[HttpPost]
[AllowAnonymous]
//[ValidateAntiForgeryToken] <-- Commented out to try to gain access from Cordova.
public async Task<ActionResult> AppLogin(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Require the user to have a confirmed email before they can log on.
// var user = await UserManager.FindByNameAsync(model.Email);
var user = UserManager.Find(model.Email, model.Password);
if (user != null)
{
if (!await UserManager.IsEmailConfirmedAsync(user.Id))
{
string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Account Registration - Confirm your account-Resend");
// Uncomment to debug locally
// ViewBag.Link = callbackUrl;
ViewBag.errorMessage = "You must have a confirmed email to log on. "
+ "The confirmation email has been resent to your email account.";
return View("Error");
}
var currentUser = UserManager.FindByName(model.Email);
bool roleresult = UserManager.IsInRole(currentUser.Id, "Customer");
if (roleresult == false)
{
ViewBag.errorMessage = "You do not have Customer Account Accesss for this site. "
+ "Please contact the Support Team.";
return View("Error");
}
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return AppRedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
private ActionResult AppRedirectToLocal(string returnUrl)
{
return RedirectToAction("Index", "Customer");
}
My View Code is below.
<section id="loginForm">
#using (Html.BeginForm("AppLogin", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Password, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
#Html.LabelFor(m => m.RememberMe)<text> </text>
#Html.CheckBoxFor(m => m.RememberMe)
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-ok"></span> Log In</button>
</div>
</div>
<p>
#Html.ActionLink("Register as a new user", "Register")
</p>
<p>
#Html.ActionLink("Forgot your password?", "ForgotPassword")
</p>
}
</section>
My Apache Cordova code is simple below.
<form action="https://nameofmywebsite.azurewebsites.net/Account/AppLogin/" class="form-horizontal" method="post" role="form">
<input name="__RequestVerificationToken" type="hidden" value="" /> <!-- Left this code in but do not think it is required. -->
<hr />
<input id="Email" name="Email" type="text" value="andy#galleos.co.uk" />
<input id="Password" name="Password" type="password" value="Andy.1234" />
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
<label for="RememberMe">Remember me?</label><text> </text>
<input data-val="true" data-val-required="The Remember me? field is required." id="RememberMe" name="RememberMe" type="checkbox" value="true" />
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-ok"></span> Log In</button>
</div>
</div>
<p>
Register as a new user
</p>
<p>
Forgot your password?
</p>
</form>
I can now see the username and password passed to the form and filled in correctly.
The key problem, I want to open the form Action within a cordova.InAppBrowser.open session as I do not have access to the browser controls opening within the app.
Also I would greatly appreciate anybody advising me on how to write a web api to auto log in to my MVC site and then potentially get authorisation and pass data backwards to my mobile app ?
I know the scope of this question is broad my apologies, I just need a foot hold to nudge me in the correct direction.
I have looked in to Azure Mobile Services and this seems like a good way to go, but I can not find any reference to help me authorise my users using the existing process within my MVC site.
Many thanks in advance for suggestions/links or slaps in the correct direction.
#Andy,
this is a common misunderstanding with Cordova/Phonegap. While you are using a webview (library) to do the rendering, there is NO need to use a CGI. You can infact do the same with an AJAX call or a REST API. This means your MVC code, while pretty, is a complete waste. You can do everything you need with Javascript and AJAX.
I would suggest you learn about AJAX, because while Javascript is foreign to most programmers, once they understand it, they get it.
Microsoft should have something equivalent to this
https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started
One last thing, the AJAX system is Asynchronous, NOT synchronous. This means the system is event-driven and not linear. If you need clarity on Asynchronous, please ask.
Best of Luck

Categories

Resources