Reputation: 137
What i got is:
var post = function(id, message, username, date) {
this.id = id;
this.message = message;
this.username = username;
this.date = date;
this.comments = ko.observableArray([]);
this.addComment = function(context) {
var comment = $('input[name="comment"]', context).val();
if (comment.length > 0) {
$.connection.boardHub.server.addComment(this.id, comment, vm.username())
.done(function() {
$('input[name="comment"]', context).val('');
});
}
};
And View:
<form class="add-comment" data-bind="submit: addComment">
<div class="row">
<div class="col-md-9">
<input type="text" class="form-control" name="comment" placeholder="" />
</div>
<div class="col-md-3">
<button class="btn btn-default" type="submit">Answer</button>
</div>
And the question is how can i pass to addComment extra value without missing context? Like:
<form data-bind="submit: function(){ writePost(<context>, '@ViewBag.UserN'); }">
Upvotes: 0
Views: 1886
Reputation: 2929
As I mentioned in my comment, you are not using knockout correctly. Therefore I'll provide you with a generic example of how you should handle form submits using knockout.
First, you should define a viewmodel which wraps your UI data and connects to services to do any actual logic. In simple cases, many people just write the logic, such as API calls right into the viewmodel instead of a service. For simplicity, I'll just do that, because extracting it into its own 'class' should be simple enough. You should give your viewmodel a more descriptive name than post
. Here is an example:
var commentViewModel = function(id, userName) {
var self = this;
this.commentText = ko.observable('');
this.addComment = function() {
var txt = self.commentText();
if (txt) {
$.connection.boardHub.server.addComment(id, txt, userName)
.done(function() {
self.commentText('');
});
}
};
};
var commentVM = new commentViewModel('@ViewBag.Id', '@ViewBag.UserN');
$(function() { ko.applyBindings(commentVM); });
HTML:
<form class="add-comment" data-bind="submit: addComment">
<div class="row">
<div class="col-md-9">
<input type="text" class="form-control" data-bind="textInput: commentText" />
</div>
<div class="col-md-3">
<button class="btn btn-default" type="submit">Answer</button>
</div>
</div>
</form>
Explaination:
The commentVM
object contains a commentText
member. This is a KO observable, so by exposing it by assigning it to this
, you can bind to it. Then you can read the value of it by utilizing the KO binding mechanism instead of mixing jQuery and KO. Bindings exist to simplify your life not to be mixed with plain jQuery stuff, so you should use them wherever you can.
You should also expose an observable array to hold the actual comments, but since that wasn't part of your question I didn't want to introduce it to exclude any additional noise which is not related to what you asked.
In your HTML, you used the submit
binding correctly. By binding the submit
event to the addComment
method, this method will get invoked correctly. But what's different compared to your code is that you read the comment text from the observable you've just defined, and avoid using jQuery. Since the VM itself is the context, you don't have to care about how to pass it -- that is, anything that you intend do use from within the submit method should generally be included in the viewmodel.
If, for whatever reason, you need to pass any extra parameter - such as dynamic content generated by Razor, for example, you can use the bind
method. You can read more about it here, it is written just above Note 3. I'd like to note that even though it is documented in the click
binding page, you can use it with submit as well (in fact, with any binding that binds to a method). Just for clarity, I'll include the relevant part here as well:
<button data-bind="click: myFunction.bind($data, 'param1', 'param2')">
Click me
</button>
So all you have to do is to specify the function to which you want to bind, and append a .bind($data, parameter1, parameter2,....)
expression to it. Note that here, $data
is the context; you should always include it in the .bind
call. However, this will not be passed to any method parameter, it is necessary for KO to do its magic, so if you had a function like this:
function a(x,y,z)
then x
would be passed param1
, y
would be passed param2
and z
wouldn't be passed anything. If you want to force passing $data
, you should include it twice in the bind
call as such: .bind($data, $data, ....more params)
.
Upvotes: 1