I'm using Durandal with the observable plugin enabled to utilize ES5 getters and setters. I've created a simple widget that takes a value and binds it to a text box:
Here's the widget's viewmodel.js:
define([], function () {
var ctor = function () {
this.activate = function (settings) {
this.value = settings.value;
}
};
return ctor;
});
And here's the widget's view.html:
<span>
This textbox is in the widget:
<br />
<input type="text" data-bind="value: value" />
</span>
When using the widget, if the value is passed in as a ko.observable, then everything works as expected. However, if I use the ES5 getter/setter method provided by the observable plugin, modifying the value in the widget does not cause the parent view model to be updated. Modifying the value in the parent view does update the widget though:
define(['durandal/app', 'knockout'], function (app, ko) {
var ctor = function () {
this.value = ko.observable('Test'); // This works as expected
this.value = 'Test'; // This does not work
};
return ctor;
});
Here's the parent view:
<section>
<h1>Widget Test</h1>
This textbox is not in the widget:
<br />
<input type="text" data-bind="value: value" />
<br /><br />
<div data-bind="widget: { kind: 'testWidget', value: value }"></div>
</section>
Am I doing something wrong that is preventing the value from being pushed back to the parent view model?
You will have to define/use a observable property to make it two-way binding so that the changes made in view will be reflected in your View Model.
this.value = ko.observable('Test'); works for your requirement.
Related
I have a form that can have different state based on which button was used for submission; one does a simple submit while the other one adds a flag then submit.
I found a working solution that is, imo, quite ugly, so I'd like to know how else to do it ?
class MyForm extends Component {
// Hijack submit to add published flag
handlePublish = (e) => {
e.preventDefault();
const { handleSubmit, onSubmit } = this.props;
handleSubmit((values) => {
onSubmit({
...values,
isPublished: true,
});
})();
}
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit}>
<Field
name="foo"
component="input"
/>
<button
type="submit"
onClick={this.handlePublish}
>
Publish
</button>
<button type="submit">
Save
</button>
</form>
);
}
}
✅ This is the idiomatic way. Alternatively, you could provide any number of values as initialValues that don't actually have a Field on the form, but will be submitted.
I am working with the jQuery TE plugin (http://jqueryte.com/). It does not seem to work with the jQuery Validation plugin.
A regular textarea works fine but if I want to transform it into a jqte WYSIWYG I lose that functionality.
In this example the Name and Bio fields are validated, but not the Resume field.
jsFiddle
Html:
<form id="frmExample">
<div><b>Name:</b></div>
<input name="txtName" id="txtName" class="required" />
<br />
<div><b>Bio:</b></div>
<textarea cols="40" rows="6" name="txtBio" id="txtBio" class="required"></textarea>
<br />
<div><b>Resume</b></div>
<textarea name="txtResume" class="required" id="txtResume"></textarea>
<br />
<br />
<input type="submit" value="Save" />
JS:
$("#txtResume").jqte();
$("#frmExample").validate();
I have detailed an example of this in a blog post: http://chadkuehn.com/jquery-te-validation/
When you place a jqte on a TEXTAREA tag it hides the original element. So in the validation plugin you must adjust the markup that's visible when highlighting and unhighlighting. You must also do some adjusting to the placement of the error label.
errorPlacement: function (error, element) {
var el = $(element).closest(".jqte");
if (el.length == 1) {
error.insertAfter(el);
} else {
error.insertAfter(element);
}
},
highlight: function (element, errorClass, validClass) {
$(element).addClass(errorClass).removeClass(validClass);
var el = $(element).closest(".jqte");
if (el.length == 1) {
el.addClass(errorClass);
}
},
unhighlight: function (element, errorClass, validClass) {
$(element).removeClass(errorClass).addClass(validClass);
var el = $(element).closest(".jqte");
if (el.length == 1) {
el.removeClass(errorClass);
}
}
View a DEMO here.
Using ASP.NET MVC I would recommend this...
To have jQuery validation automatically with jqte, execute at startup:
$('.jqte_editor').change(function () {
if ($(this).parent().siblings('.textarea-editor').hasClass('.input-validation-error'))
$(this).parent().addClass('input-validation-error');
else
$(this).parent().removeClass('input-validation-error');
});
$('form').bind('submit', function () {
$('.textarea-editor.input-validation-error').parent().parent().addClass('input-validation-error');
$('.textarea-editor:not(.input-validation-error)').parent().parent().removeClass('input-validation-error');
});
And remember to put "textarea-editor" class in the textarea
I have three partial views within a view that are toggled via radiobutton selection. Each partial view has it's own submit input and two of the partial views contain a tinyMCE textarea. When I only had one partial that contained a tinyMCE textarea, I was able to get that textarea to validate using .triggerSave(), but now that I have added the second tinyMCE textarea, I can't get either of the tinyMCE textareas to pass validation.
I tried many of the solutions found on similar questions here on SO, but I have not been successful in getting these textareas to pass validation.
Here is the tinyMCE pertinent code on the first partial:
<script type="text/javascript">
$(document).ready(function () {
tinyMCE.init({
mode: "specific_textareas",
editor_selector: "mceEditorForAddRow",
theme: "simple",
width: "500",
height: "300"
});
});
#using(Html.BeginForm("_AddSchemaRow","Database_Schema")
{
#Html.ValidationSummary(true)
<script type="text/javascript">
$("#CreateRow").click(function () {
tinyMCE.triggerSave();
});
</script>
<table>
....
....
<tr>
<td>
#Html.LabelFor(model => model.SchemaElement)
</td>
<td>
#Html.TextAreaFor(model => model.SchemaElement, new { #class = "mceEditorForAddRow" })
#Html.ValidationMessageFor(model => model.SchemaElement)
</td>
</tr>
....
....
</table>
<p>
<input id="CreateRow" type="submit" value="Create" />
</p>
}
Here is the contoller's action for this first partial:
public ActionResult _AddSchemaRow(int id)
{
SchemaRow schemaRow = new SchemaRow();
schemaRow.DatabaseSchemaID = id;
schemaRow.SchemaIndex = DatabaseSchema.GetSchemaHeadersByDatabaseSchemaID(id).Count() + 1;
return PartialView(schemaRow);
}
Here is the controller's POST action for this first partial:
[HttpPost]
[ValidateInput(false)]
public ActionResult _AddSchemaRow(SchemaRow schemaRow)
{
if (ModelState.IsValid)
{
DatabaseSchemaViewModel vm = new DatabaseSchemaViewModel(DatabaseSchema.GetDatabaseSchemaByID(schemaRow.DatabaseSchemaID));
vm.SchemaRowsAndHeaders = DatabaseSchemaViewModel.GetSchemaRowsAndHeadersBySchemaID(schemaRow.DatabaseSchemaID);
if (SchemaRow.Create_SchemaRow(schemaRow))
{
return RedirectToAction("Edit", new { id = schemaRow.DatabaseSchemaID });
}
else
return PartialView(schemaRow);
}
else
return PartialView(schemaRow);
}
The second partial is set up just like the first partial above, except contains a "SchemaHeader" rather than a "SchemaRow" in all applicable fields including the submit input id being "CreateSchemaHeader". I think example code should provide enough description of my problem. I can add the other partial's code if needed. Thanks in advance for any help in finding a solution.
I was able to finally figure it out. The solution was to add click function after the input that the input that causes the postback.
Example:
<p>
<input id="CreateRow" type="submit" value="Create" />
</p>
<script type="text/javascript">
$("#CreateRow").click(function () {
tinyMCE.triggerSave();
});
</script>
Trying to get an event triggered with ajax content whose parent elements were also ajax loaded.
<div id="content"><!-- NOT ajax-loaded -->
<div id="location"> <!-- #location IS ajax-loaded -->
<div id="add_location> <!-- #add_location IS ajax-loaded from a #location event -->
<input type="text" id="add_location_city_example" />
<input type="text" id="add_location_state_example" />
<input type="submit" id="add_location_confirm" />
</div>
</div>
</div>
$(function(){
$('#content').on('click', '#add_location_confirm', function(){
console.log('debug 1');
add_location();
// will not be called
});
$('#location').on('click', '#add_location_confirm', function() {
console.log('debug 2');
// will not be called either
add_location();
});
});
If I have onclick="add_location()" and function add_location() { console.log('debug 3); } in my .js then it will obviously be called BUT I then cannot get $('#add_location_city_example').val() because none of it will be in the dom.
NOTE: using 1.9.1
I've been using this for a while, makes it much easier to handle situations like you are describing + there is only one even assignment for pretty much all clicks on the page, including elements that will appear on the page in the future:
$(document).bind('click', function (e) {
var target = $(e.target);
if (target.is('#content')) {
e.preventDefault();
// do whatever
} else if (target.is('#location')) {
e.preventDefault();
// do whatever else
}
});
or in your case it would probably be more like this:
$(document).bind('click', function (e) {
var target = $(e.target);
if (target.is('#add_location_confirm')) {
e.preventDefault();
if (target.closest('#location').length == 0) { // not yet have location injected via ajax
// do something
} else {
// location has been injected, do something else
}
});
I have the following JSFiddle example. How do I dispose of a KendoUI DropDownList?
http://jsfiddle.net/bryanb/bWRTm/1/
I have tried the following without luck:
supplier: <input id="suppliers1" class="suppliers" value="2" />
<br />
supplier: <input id="suppliers2" class="suppliers" value="2" />
<br />
<button id="dispose">Dispose</button>
js:
function comboboxDispose() {
$(".suppliers").each(function () {
var combobox = $(this).data("kendoComboBox"),
popup = combobox.popup,
element = popup.wrapper[0] ? popup.wrapper : popup.element;
//remove popup element;
element.remove();
//unwrap element
combobox.element.show().insertBefore(combobox.wrapper);
combobox.wrapper.remove();
combobox.element.removeData("kendoComboBox");
});
}
I figured this out. My selector was selecting the wrong elements after my kendoui combobox was initialized. Here is the fix:
function comboboxDispose() {
$("input[class='suppliers']").each(function () {
var combobox = $(this).data("kendoComboBox"),
popup = combobox.popup,
element = popup.wrapper[0] ? popup.wrapper : popup.element;
//remove popup element;
element.remove();
//unwrap element
combobox.element.show().insertBefore(combobox.wrapper);
combobox.wrapper.remove();
combobox.element.removeData("kendoComboBox");
});
}
Working Example:
http://jsfiddle.net/bryanb/bWRTm/2/