The goal
Get an object with submit binding of KnockoutJS.
The problem
I need to get the object instead of the element when I submit some form.
Here, on jsFiddle, open your console and then click on add button of some item. You'll receive the Products object and here everything is right. But here, also in jsFiddle, when you click on add button your response will be the element instead of the object — and I need the object.
The difference between the codes
Look to this function when I add:
self.add = function (item) {
var i = self.products.indexOf(item);
self.products()[i].isAdded(true);
};
But, when the binding is submit, the item parameter is different from response that click binding returns.
My scenario
In my real application, there is two ViewModels like this. I thought it would be simpler, but unfortunately, it isn't.
Someone have any idea?
You need to pass in the $data object when calling the function on the submit. Otherwise it will automatically pass the form object.
For example:
<!-- ko ifnot:isAdded -->
<form data-bind="submit: function() { $parent.add($data); }">
<button data-bind="ifnot:isAdded" class="btn btn-small action add">
<i class="icon-plus">Add</i>
</button>
</form>
<!-- /ko -->
Here's a working update to your fiddle: http://jsfiddle.net/G8zPT/4/
Related
I have a page with a button, I have a binding on the button that executes some ajax calls sending some data.
The code with the binding is rather generic and reused in several other spots in the application. So I can't change its current behaviour (I could change it in a way that won't affect other users of this).
I have now a requirement to change the behaviour of one of the pages that use this binding (i.e. I shouldn't change the binging in a way that breaks the other pages).
Now I need the button in a specific page to not submit the data in case some other conditions are not met. (in specific instead of submitting, I need to show a modal, with a double check if they really want to complete the submission)
I made an executable snippet which explains it:
$('button').click(function (e) {
$('ul').append('<li>submitting data</li>');
});
$('button').click(function (e) {
if($(this).data('value') != 'ready') {
$('ul').append('<li>condition not met, data not submitted</li>')
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>
When the button is clicked, I want the data
to be submitted only if the condition is not met.
</p>
<p>
In this example I need 'condition not met'
to be printed, and not 'submitting data'.
</p>
<button data-value='not-ready'>
content
</button>
<ul>
</ul>
I need that this specific page doesn't submit the data in case the condition is not met.
How could I get this?
Not sure if this is what you're looking for - done with the assumption that you might not want to change the structure of the button's HTML. You could set one of its outer containers to something you could test for - and then along those lines, you could also set a dynamic validation function to call for the button inside the container.
$('button').click(function(e) {
if ($(this).closest('.validate-extra').length > 0) {
if ($(this).closest('.validate-extra').data('fn')) {
return window[$(this).closest('.validate-extra').data('fn')]();
} else {
console.error('no special validation function in scope!');
}
} else $('ul').append('<li>submitting data</li>');
});
function val1() {
console.log('running function val1()');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>
When the button is clicked, I want the data to be submitted only if the condition is not met.
</p>
<p>
In this example I need 'condition not met' to be printed, and not 'submitting data'.
</p>
<button data-value='not-ready'>
content
</button>
<div class='validate-extra' data-fn='val1'>
<button data-value='not-ready'>
content
</button>
</div>
<ul>
</ul>
Following #aleksG suggestion in the comments I ended up with quite a bit of changes, but mainly:
move the code that does the data submission to a function, that can be called from anywhere
have each of the pages that use that function load the binding independently (the binding was there globally earlier)
have a new binding on a new css class that handles the validations before (eventually) calling the code submission
This worked and looks rather clean.
Thanks.
I'm making a little app in meteor to store car inspection registries, it uses an "autoform" form to insert the values that i need then i present those values somewhere else, one of my templates presents all items stored in the collection and i managed to make a "details" button that shows a modal that should have more details.
App screenshot
Modal Screenshot
Currently i have a hidden field with the id from the item in the collection, i send that id with a session and the template with the modal gets that session.
<form>
<button type="submit" class="btn btn-md btn-warning" ><i class="fa fa-list"></i> Detalles</button> //submit button
<input type="hidden" name="idp" value={{_id}} size="1"> //Hidden field with item id
</form>
It's working just fine, the problem is that i need the other buttons in the panel to act differently, yet all of them need the id from the item in the collection. The only way i know how to catch the contents from an element in a template is through event.target."elementName".value and this only works with the submit event i think, i tried document.getElementById with the click event but that only showed the first item in the collection, even if i clicked on the "details" button of another item.
The event code:
Template.Inspeccion.events({
'submit form'(events){
event.preventDefault();
var id= event.target.idp.value;
Session.set('id-carro', id);
Modal.show('Detalles');
},
The modal code:
Template.Detalles.helpers({
carro: ()=> {
var id= Session.get('id-carro');
return Inspeccion.findOne({_id:id});
},
});
Is there anyway to listen to different submit buttons or is there any other way to extract the contents from the template and use a different event that will work per button?
I'm pretty sure i'm missing something obvious but i can't find a solution online.
Thanks in advance and Happy Holidays.
You can define click events on buttons and refer to the current data context with this in your javascript. Ex:
html:
<button id="foo">click me</button>
js:
Template.Inspeccion.events({
'click #foo'(){
console.log(this._id); // "this" will be the data context that was clicked on
}
});
I am very new in JavaScript and I have the following doubt about how exactly work this script that submit a form:
So in my html I have the following form:
<form id="actionButton<%=salDettaglio.getCodice()%>" action="salwf.do?serv=1" method="post">
<button id="accept" name="ctrl" value="Accept" type="submit" class="acceptButton" onclick="sottometti(this,'<%=salDettaglio.getCodice()%>')">ACCEPT ICON BUTTON</button>
<button id="cancel" name="ctrl" value="Cancel" type="submit" class="cancelButton" onclick="sottometti(this)">CANCEL ICON BUTTON</button>
<button id="sap" name="ctrl" value="SAP" type="submit" class="sapButton" onclick="sottometti(this)">SAP ICON BUTTON</button>
<input id="testId<%=salDettaglio.getCodice()%>" name="test" type="hidden">
</form>
So the submission of this form is directed towards a page salwf.do and each time pass a parameter named serv and having 1 as value (is this a GET?)
Then inside the form I have 3 buttons having different id and different values and the input tag (that I think it is what I am submitting, is it right?)
As you can see when the user click on a button is called the sottometti(this) script that take as parameter the reference to the object that have generated the click (in this case the clicked button)
And this is this JavaScript code:
function sottometti(obj,id){
document.getElementById('testId'+id).value = obj.value;
document.getElementById('actionButton'+id).submit()
}
So how exactly work this script?
I think that it do the following thing (but I am not sure about it and maybe I am missing something).
It take 2 input parameters: the clicked button reference (obj) and the id string (that represent a code of a Java object, but this is not important now).
Using:
document.getElementById('testId'+id)
it retrieve the reference of the input tag of the form and set the value (what I want submit) with the button value (that can be: Accept or Cancel or Sap)
Then by:
document.getElementById('actionButton'+id)
retrieve my form and submit it
So the value of the clicked button will be submitted to the salwf.do servlet as POST.
Is it my reasoning correct or am I missing something?
Tnx
Yes your reasoning is correct, but you have some issues.
you only pass the ID from one of the buttons - the accept one
For all buttons you seem to want to add Accept/Cancel/SAP to a hidden field called testAccept, testCancel or testSAP and submit a form with ID actionButtonAccept, actionButtonCancel, actionButtonSAP but do not have either the field nor the form in the Cancel/SAP situation.
do not submit in a click event of a submit button
I would do
function sottometti(obj){
obj.form.test.value = obj.value;
// obj.form.submit(); // all the buttons are submit buttons
}
Be careful about one thing. Here you attach JavaScript to button[type=submit] and you execute form submit. So in fact you submit it twice.
If you want to prevent submission you should at least return false in your callback function (best is anyhow to use event.preventDefault();) like in that answer https://stackoverflow.com/a/23646215/2802756
I have just started using Knockout.js My form has elements which I call questions. I hide/show them based on user selections. When user hits the submit button I want to post only the visible questions at the time of submit. What I have is this:
// length of Results(questionArray) is 260
var vmToPost = viewModel;
delete vmToPost.__ko_mapping__;
ko.utils.arrayForEach(vmToPost.Results(), function (question) {
if (!(vmToPost.getQuestion(question.QuestionID()).visible())) {
ko.utils.arrayRemoveItem(vmToPost.Results(), question);
}
});
The util function arrayForEach is behaving strange. It loops through the array very differntly. I had to hit the submit button 7 times to get all the visible elements and come out of the util function. It doesnt throw any error message in the console or the fiddler.
What am I doing wrong. Please help.
Html contains a built-in way to skip items from being submitted. It's the disabled attribute, which can be controlled using Knockout with the enable or disable bindings.
<div data-bind="visible: visible">
<label>Name: <input name="name" data-bind="enable: visible"></label>
</div>
when using the click bind in knockout, how does knockout know to pass the correct parameter to the method its bound to?
<div id="test" data-bind="click: runTest"/>
</div>
self.runTest = function (coolParameter){
doSomethingCool();
}
When calling your handler, Knockout will supply the current model
value as the first parameter. This is particularly useful if you’re
rendering some UI for each item in a collection, and you need to know
which item’s UI was clicked.
from the documentation
There also is some discussion in the docs about how to pass more parameters by adding a wrapping function
<button data-bind="click: function(data, event) {
myFunction('param1', 'param2', data, event)
}">
Click me
</button>
knockout understands which value to pass from context. it's the current model object. e.g if you're in a foreach knockout passes the current item.