I’ve got a Rails 3.2 app which I’ve started to attach a lot of knockout.js bindings to. I would like to submit the form in JSON format to my Rails server.
I have a transaction form which has an amount
= form_for(@tran, :html => {"data-bind" => "submit: submitTrans"}) do |f|
.field
= f.label :date
= f.date_select :date
.field
= f.label :voucher
= f.number_field :voucher
.field
= f.label :amount
= f.text_field :amount, "data-bind" => "value: amount, valueUpdate: 'afterkeydown', style: { background: amount() == 0 ? 'red' : 'white' }"
.field
= f.label :tax
= f.text_field :tax, "data-bind" => "value: tax"
.actions
= f.submit 'Save'
Here is my knockout code:
#= require knockout
TranViewModel = ->
# Observables
self.amount = ko.observable("0")
# Computed values
self.tax = ko.computed(
read: -> (self.amount() / 10).toFixed 2
write: (value) -> value
owner: this)
tranViewModel = new TranViewModel()
# Submit through AJAX
self.submitTrans = (formElement) ->
alert ko.toJSON(tranViewModel)
# Apply keybindings on page load
$(document).ready (event) ->
ko.applyBindings(tranViewModel)
When I’m using ko.toJSON like this I get ‘undefined’ returned in my alert box.
Do I have to create an instance of my model?
How do I get all my form attributes in JSON format and post these to my rails route ‘/transaction’?
The knockout documentation describes a pushJSON feature but the page doesn’t exist anymore:
http://knockoutjs.com/documentation/submit-binding.html
Update #1
I tried manually sending the json and this allowed me to create an object
self.submitTrans = (formElement) ->
json = JSON.parse('{"tran": {"amount": "9999"}}')
$.post("/trans", json, (returnedData) ->
alert returnedData)
Update #2
I tried a number of things to get my form into JSON for submitting using $.post
self.submitTrans = (formElement) ->
json = ko.toJSON(tranViewModel)
$.post("/trans", json, (returnedData) ->
alert returnedData)
This comes back as undefined. What do I pass to the ko.toJSON?
Update #3
I tried the example from the knockout website:
viewModel =
firstName : ko.observable("Bert"),
lastName : ko.observable("Smith"),
pets : ko.observableArray(["Cat", "Dog", "Fish"]),
type : "Customer"
self.submitTrans = (formElement) ->
json = ko.toJSON(viewModel)
$.post("/trans", json, (returnedData) ->
alert returnedData)
This correctly formats the viewModel as JSON. This is because viewModel is an object not a function. If I however change my TranViewModel from a function to an object this breaks a lot of my bindings. Which is the correct way of setting up my bindings? Should they be in an object or a function?
Update #4
My examples:
jsfiddle.net/p6Vcc/3 – When clicking submit the ko.toJSON does not collect all formElements, should I be adding observable to all my fields?
jsfiddle.net/p6Vcc/4 – Same example as the previous except recoded in coffeescript, now when clicking the submit it only shows the customers last name, and none of the other fields.
UPDATE 1
So looking at the coffee script provided above in the jsfiddle, there is an issue with the javascript being generated by the coffeescript:
Coffeescript always returns the last statement, so you have to add a @ at the end to “return this”
resulting javascript
Original Answer
I’m not sure where you are having the trouble. I put your code above into a jsfiddle and it works as expected.
http://jsfiddle.net/JasonMore/p6Vcc/2/
Can you update the fiddle to reflect the problem you are having?
Javascript