How to get Knockout dialog to update - javascript

I got this dialog popup that I want to update with a selected Text.
<div data-bind="with: SelectedText">
<div id="dialog" data-bind="dialog: {'autoOpen': false, 'title': textbatchTitle }, dialogVisible: $root.isMetadataDialogOpen">
<div class="metadata">
<label for="textbatchTitle">Title:</label> <span class="rotten">Why isen´t this updated with SelectText after pushing "Add New Text"?"</span>
<input type="text" name="textbatchTitle" data-bind="value: textbatchTitle, valueUpdate: 'afterkeydown'" />
</div>
</div>
</div>
It seems the dialog does´t respond to the "with"-binding?
This is my custom binding:
ko.bindingHandlers.dialog = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = ko.utils.unwrapObservable(valueAccessor()) || {};
//do in a setTimeout, so the applyBindings doesn't bind twice from element being copied and moved to bottom
setTimeout(function () {
options.close = function () {
allBindingsAccessor().dialogVisible(false);
};
$(element).dialog(ko.toJS(options));
}, 0);
//handle disposal (not strictly necessary in this scenario)
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).dialog("destroy");
});
},
update: function (element, valueAccessor, allBindingsAccessor) {
var shouldBeOpen = ko.utils.unwrapObservable(allBindingsAccessor().dialogVisible),
$el = $(element),
dialog = $el.data("uiDialog") || $el.data("dialog"),
options = valueAccessor();
//don't call dialog methods before initilization
if (dialog) {
$el.dialog(shouldBeOpen ? "open" : "close");
for (var key in options) {
if (ko.isObservable(options[key])) {
$el.dialog("option", key, options[key]());
}
}
}
}
};
What is wrong with this?
http://jsfiddle.net/qFjRW/

You didn't include jquery ui as an external source:
Uncaught TypeError: Object [object Object] has no method 'dialog'
See http://jsfiddle.net/FXTHn
EDIT:
Since you're using the with: SelectedText outside of the dialog, it won't call update when SelectedText changes. Try placing it inside:
<div id="dialog" data-bind="dialog: {'autoOpen': false, 'title': SelectedText().textbatchTitle }, dialogVisible: $root.isMetadataDialogOpen">
<div data-bind="with: SelectedText">
<div class="metadata">
<label for="textbatchTitle">Title:</label> <span class="rotten">Why isen´t this updated with SelectText after pushing "Add New Text"?"</span>
<input type="text" name="textbatchTitle" data-bind="value: textbatchTitle, valueUpdate: 'afterkeydown'" />
</div>
</div>
</div>
http://jsfiddle.net/FXTHn/1/

Related

Kendo UI javascript : remote bind form

I'm having trouble getting started with binding a Form to a remote Datasource in Kendo UI for javascript
I have verified that the ajax call returns the correct JSONP payload, e.g:
jQuery31006691693527470279_1519697653511([{"employee_id":1,"username":"Chai"}])
Below is the code:
<script type="text/javascript">
$(document).ready(function() {
var viewModel = kendo.observable({
employeeSource: new kendo.data.DataSource({
transport: {
read: {
url: baseUrl + "/temp1",
dataType: "jsonp"
},
parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
return {
models: kendo.stringify(options.models)
};
}
return options;
}
},
batch: true,
schema: {
model: {
id: "employee_id",
fields:{
employee_id: { type: "number" },
username: { type: "string" }
}
}
}
}),
hasChanges: false,
save: function() {
this.employeeSource.sync();
this.set("hasChanges", false);
},
change: function() {
this.set("hasChanges", true);
}
});
kendo.bind($("#item-container"), viewModel);
viewModel.employeeSource.read();
});
</script>
<div id="item-container">
<div class="row">
<div class="col-xs-6 form-group">
<label>Username</label>
<input class="form-control k-textbox" type="text" id="username" data-bind="value: username, events: { change: change }" />
</div>
</div>
<button data-bind="click: save, enabled: hasChanges" class="k-button k-primary">Submit All Changes</button>
</div>
No errors are thrown, but I was expecting my username text form field to be populated with the value 'Chai', and so on.. but it doesn't
Your textbox is bound to a username property but this doesn't exist on your view-model, nor is it being populated anywhere. Assuming your datasource correctly holds an employee after your call to read(), you will need to extract it and set it into your viewmodel using something like this:
change: function(e) {
var data = this.data();
if (data.length && data.length === 1) {
this.set("employee", data[0]);
this.set("hasChanges", true);
}
}
And modify the binding(s) like this:
<input class="form-control k-textbox" type="text" id="username"
data-bind="value: employee.username, events: { change: change }" />
You should also be aware that the change event is raised in other situations, so if you start using the datasource to make updates for example, you'll need to adapt that code to take account of the type of request. See the event documentation for more info. Hope this helps.

Login with enter key pressed knockout js

I have been trying to get my login page to work once I pressed the enter key, but it doesn't work. Help anyone?
Here is my codes:
Javascript/ viewModel:
ko.bindingHandlers.enterkey = {
init: function (element, valueAccessor, allBindings, viewModel) {
var callback = valueAccessor();
$(element).keypress(function (event) {
var keyCode = (event.which ? event.which : event.keyCode);
if (keyCode === 13) {
callback.call(viewModel);
return false;
}
return true;
});
}
};
Mobile.Login = function (params) {
var viewModel = {
dxPasswordTB: {
value: ko.observable(""),
showClearButton: true,
placeholder: ko.observable("PASSWORD"),
mode: 'password'
},
validateAndSubmit: function (params) {
var result = params.validationGroup.validate();
...
},
};
return viewModel;
};
View/ HTML:
<div class="row">
<div class="col-sm-12 col-xs-12">
<div class="form-group">
<div class="input-group">
<span class="input-group-addon"><i class="icon-password"></i></span>
<div class="form-control">
<div data-bind="dxTextBox: dxPasswordTB, dxValidator: PasswordVR, valueUpdate: 'afterkeydown', enterkey: validateAndSubmit""></div>
</div>
</div>
</div>
</div>
</div>
Any idea what went wrong here? If you do, please post your suggestions here, thanks!
I managed to resolve this by using onEnterKeyin dxPasswordTB from devExpress. Also, I changed params.validationGroup.validate(); to DevExpress.validationEngine.validateGroup() and the value was finally defined.

datetimepicker bootstrap minDate and maxDate in observable knockout

I am using the plugin bootstrap-datetimepicker with knockout js. I've done a handler to dynamically manage and MaxDate MinDate, as I show below:
ko.bindingHandlers.dateTimePicker = {
init: function (element, valueAccessor, allBindingsAccessor) {
//initialize datepicker with some optional options
var options = allBindingsAccessor().dateTimePickerOptions || {};
$(element).datetimepicker(options);
//when a user changes the date, update the view model
ko.utils.registerEventHandler(element, "dp.change", function (event) {
var value = valueAccessor();
if (ko.isObservable(value)) {
if (event.date && event.date != null && !(event.date instanceof Date)) {
value(event.date.toDate());
} else {
//value(event.date);
value(undefined);
}
}
});
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
var picker = $(element).data("DateTimePicker");
if (picker) {
picker.destroy();
}
});
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var picker = $(element).data("DateTimePicker");
//when the view model is updated, update the widget
if (picker) {
//Usamos moment para convertir a fecha ya que utiliza este plugin adicional datetimepicker
var koDate = moment(ko.utils.unwrapObservable(valueAccessor()) || '');
if (koDate.isValid()) picker.date(koDate.toDate() || null);
}
}
};
ko.bindingHandlers.minDate = {
update: function (element, valueAccessor) {
var value = moment(ko.utils.unwrapObservable(valueAccessor()) || ''),
picker = $(element).data("DateTimePicker");
if (value.isValid() && picker) {
picker.minDate(value.toDate());
}
}
};
ko.bindingHandlers.maxDate = {
update: function (element, valueAccessor) {
var value = moment(ko.utils.unwrapObservable(valueAccessor()) || ''),
picker = $(element).data("DateTimePicker");
if (value.isValid() && picker) {
picker.maxDate(value.toDate());
}
}
};
I use it as follows:
<div class="input-group" data-bind="dateTimePicker: NuevaTarea.FechaInicio, dateTimePickerOptions: { format: 'L', showClear: true }, minDate: NuevaTarea.minDate, maxDate: NuevaTarea.maxDate">
<input type="text" class="form-control" />
<div class="input-group-addon">
<i class="fa fa-calendar"></i>
</div>
</div>
The problem is when change the NuevaTarea.minDate and NuevaTarea.maxDate, the date of MaxDate is assigned to NuevaTarea.FechaInicio.
Someone could help me create an observable MaxDate MinDate and properly functioning? No I'm doing wrong.
The version of plugin is 4.15.35.
https://github.com/Eonasdan/bootstrap-datetimepicker
ko.bindingHandlers.dateTimePicker = {
init: function (element, valueAccessor, allBindingsAccessor) {
//initialize datepicker with some optional options
var options = allBindingsAccessor().dateTimePickerOptions || {};
$(element).datetimepicker(options);
//when a user changes the date, update the view model
ko.utils.registerEventHandler(element, "dp.change", function (event) {
var value = valueAccessor();
if (ko.isObservable(value)) {
if (event.date && event.date != null && !(event.date instanceof Date)) {
value(event.date.toDate());
} else {
//value(event.date);
value(undefined);
}
}
});
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
var picker = $(element).data("DateTimePicker");
if (picker) {
picker.destroy();
}
});
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var picker = $(element).data("DateTimePicker");
//when the view model is updated, update the widget
if (picker) {
//Usamos moment para convertir a fecha ya que utiliza este plugin adicional datetimepicker
var koDate = moment(ko.utils.unwrapObservable(valueAccessor()) || '');
if (koDate.isValid()) picker.date(koDate.toDate() || null);
}
}
};
ko.bindingHandlers.minDate = {
update: function (element, valueAccessor) {
var value = moment(ko.utils.unwrapObservable(valueAccessor()) || ''),
picker = $(element).data("DateTimePicker");
if (value.isValid() && picker) {
picker.minDate(value.toDate());
}
}
};
ko.bindingHandlers.maxDate = {
update: function (element, valueAccessor) {
var value = moment(ko.utils.unwrapObservable(valueAccessor()) || ''),
picker = $(element).data("DateTimePicker");
if (value.isValid() && picker) {
picker.maxDate(value.toDate());
}
}
};
function ViewModel() {
var self = this;
self.NuevaTarea = {
FechaInicio: ko.observable(),
FechaFin: ko.observable(),
minDate: ko.observable(),
maxDate: ko.observable()
};
self.NuevaTarea.minDate(new Date()) ;
//Not is working apply value null, help here!! I Like that this field is empty on start
self.NuevaTarea.FechaInicio(null);
}
ko.applyBindings(new ViewModel());
body{height:300px; padding:20px;}
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.15.35/css/bootstrap-datetimepicker.min.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.15.35/js/bootstrap-datetimepicker.min.js"></script>
<div class="form-group">
<label class="control-label">Min Date:</label>
<div class="input-group" data-bind="dateTimePicker: NuevaTarea.minDate, dateTimePickerOptions: { format: 'L', showClear: true }">
<input type="text" class="form-control" />
<div class="input-group-addon">
<i class="glyphicon glyphicon-calendar"></i>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label">Fecha Inicio:</label>
<div class="input-group" data-bind="dateTimePicker: NuevaTarea.FechaInicio, dateTimePickerOptions: { format: 'L', showClear: true }, minDate: NuevaTarea.minDate, maxDate: NuevaTarea.maxDate">
<input type="text" class="form-control" />
<div class="input-group-addon">
<i class="glyphicon glyphicon-calendar"></i>
</div>
</div>
</div>
Thanks for your help but I already solved only just set, useCurrent: false options.
<div class="input-group" data-bind="dateTimePicker: NuevaTarea.FechaInicio, dateTimePickerOptions: { format: 'L', showClear: true, useCurrent: false }, minDate: NuevaTarea.minDate, maxDate: NuevaTarea.maxDate">
<input type="text" class="form-control" />
<div class="input-group-addon">
<i class="fa fa-calendar"></i>
</div>
</div>

RadioButtonList in Ember, Binding a model property to the selected value

I've reading and trying some codes but nothing has been working like I want i to... this is the code I have right now.
index.html:
<div class="form-group">
<label for="accommodation">3.2. ACCOMMODATION (*)</label> <br />
<div>
{{view Ember.RadioButton name="accommodation" valueBinding='accommodation' selectionBinding="isSelected" value="Not Required"}}
Not Required
</div> <br />
<div>
{{view Ember.RadioButton name="accommodation" valueBinding='accommodation' selectionBinding="isSelected" value="Required"}}
Required
</div>
</div>
View radiobutton.js:
Ember.RadioButton = Ember.View.extend({
tagName: "input",
type: "radio",
attributeBindings: ["name", "type", "value", "checked:checked:"],
click: function () {
this.set("selection", this.$().val())
},
checked: function () {
return this.get("value") == this.get("selection");
if (this.get("selection") == "Required") {
$('#panelAccommodation').style.display = "block";
}
if (this.get("selection") == "Not Required") {
$('#panelAccommodation').style.display = "none";
}
}.property()
What I want from these RadioButtonLists is to be able to retrieve the value of the selected item so I can send it as a POST to a api and to use the selected value to hide/show a div dependidng on the selected value. Any ideas on how to do this?
EDIT:
I'm trying andrusieczko's code and so far I have this:
radio.js :
App.RadioView = Ember.View.extend({
tagName: 'input',
type: 'radio',
attributeBindings: ['type', 'htmlChecked:checked', 'value', 'name'],
htmlChecked: function () {
return this.get('value') === this.get('checked');
}.property('value', 'checked'),
change: function () {
this.set('checked', this.get('value'));
},
_updateElementValue: function () {
Ember.run.next(this, function () {
this.$().prop('checked', this.get('htmlChecked'));
});
}.observes('htmlChecked')
});
Ember.Handlebars.helper('radio-button', App.RadioView);
controller:
App.EventsNewController = Ember.ObjectController.extend({
acRequired: 'Required',
acNotRequired: 'Not Required',
accommodation: null,
Index.html :
<div class="form-group">
<label for="accommodation">3.2. ACCOMMODATION (*)</label> <br />
<div>
{{radio-button value=acRequired checked=accommodation}}
Not Required
</div>
<div>
{{radio-button value=acNotRequired checked=accommodation}}
Required
</div>
</div>
still not sending the selected value on the POST request.
EDIT 2:
I've written some code that in all others aspects is behaving like I want it to but it's still not binding the selected value to the property I want it to.
View radio.js:
Ember.Radio = Ember.View.extend({
tagName: "input",
type: "radio",
attributeBindings: ["name", "type", "value", "checked:checked:"],
click: function () {
this.set("selection", this.$().val())
if(this.get("selection") === "acRequired") {
$('#panelAccommodation').css("display", "block");
this.set("selection", "Required");
selectionBinding: "App.event.accommodation"
}
if (this.get("selection") === "acNotRequired") {
$('#panelAccommodation').css("display", "none");
this.set("selection", "Not Required");
selectionBinding: "App.event.accommodation"
}
if (this.get("selection") === "flRequired") {
$('#panelFlight').css("display", "block");
this.set("selection", "Required");
selectionBinding: "App.event.flight"
}
if (this.get("selection") === "flNotRequired") {
$('#panelFlight').css("display", "none");
this.set("selection", "Not Required");
selectionBinding: "App.event.flight"
}
},
checked: function () {
return this.get("value") == this.get("selection");
}.property()
});
Index.html :
<!-- Accommodation - RadioButtonList -->
<div class="form-group">
<label for="accommodation">3.2. ACCOMMODATION (*)</label> <br />
<div>
{{view Ember.Radio name="accommodation" selectionBinding='accommodation' value="acNotRequired"}}
Not Required
</div>
<div>
{{view Ember.Radio name="accommodation" selectionBinding='accommodation' value="acRequired"}}
Required
</div>
</div>
controller new.js :
App.EventsNewController = Ember.ObjectController.extend({
accommodation: "Not Required",
flight: "Not Required",
actions: {
save: function () {
var self = this;
this.get('model').set('status', 'Created');
this.get('model').save().then(function () {
self.transitionToRoute('events.table');
});
}
}
});
PS: I'm using Ember version 1.6.1
If you're not using either Ember App Kit or ember-cli, then all you have to do is:
App.RadioView = Ember.View.extend({
tagName: 'input',
type: 'radio',
attributeBindings: ['type', 'htmlChecked:checked', 'value', 'name'],
htmlChecked: function() {
return this.get('value') === this.get('checked');
}.property('value', 'checked'),
change: function() {
this.set('checked', this.get('value'));
},
_updateElementValue: function() {
Ember.run.next(this, function() {
this.$().prop('checked', this.get('htmlChecked'));
});
}.observes('htmlChecked')
});
Ember.Handlebars.helper('radio-button', App.RadioView);
Then, in your Controller:
App.IndexController = Ember.Controller.extend({
country1: 'USA',
country2: 'Singapore',
country3: 'Poland',
country: null,
});
and in your template:
{{radio-button value=country1 checked=country}}
{{radio-button value=country2 checked=country}}
{{radio-button value=country3 checked=country}}
and you can listen to the properties you passed to the helper and based on that trigger other actions.
And it can be easily used along with {{each}} :)
Does it help?
The working example (Ember 1.6.1, ember-data 1.0.0-beta.9):
https://github.com/andrusieczko/radiobutton-example.git
Disclaimer: I'm not the author of the code, I took it from somewhere some time ago.
If you can handle not using HTML <input> elements, try using this component that I wrote.
Note that I'm using Ember 1.10 and Ember-CLI.
my-template.js (controller)
import Ember from 'ember';
export default Ember.Controller.extend({
options: [Ember.Object.create({
name: "Required",
value: "1",
}), Ember.Object.create({
name: "Not Required",
value: "0",
})],
actions: {
optionChanged: function(option) {
// option.value will either be 1 or 0 in this case.
}
}
});
my-template.hbs
{{#mutex-button-set key="value" default=options.firstObject stateChanged="optionChanged" buttons=options as |button|}}
<div>{{button.name}}</div>
{{/mutex-button-set}}
mutex-button-set.hbs
{{#each button in buttons}}
<div {{bind-attr class=":mutex-button button.selected:selected"}} {{action "setSelected" button}}>
{{yield button}}
</div>
{{/each}}
mutex-button-set.js
import Ember from 'ember';
export default Ember.Component.extend({
classNames: ['mutex-button-set'],
actions: {
setSelected: function(obj) {
var key = this.get("key");
this.get("buttons").forEach(function(button) {
Ember.set(button, "selected", obj && (button.get(key) === obj.get(key)));
});
if (obj) {
this.sendAction('stateChanged', obj);
}
}
},
didInsertElement: function() {
this.send("setSelected", this.get("default"));
}
});
HTML Generated
<div id="ember554" class="ember-view mutex-button-set">
<div data-ember-action="559" class="mutex-button selected">
<div>Required</div>
</div>
<div data-ember-action="563" class="mutex-button ">
<div>Not Required</div>
</div>
</div>

How to enable/disable save button of backbone form-view when user changes form content

I have form which gets data from backbone model. When the form is shown, they have initially value set to backbone model. Now, if any field is edited, i want to enable "save" button immediately as soon as any changes is made to field. However, if you change field value and again change it to original, it should again disable the "save" button that allows to save model.I want to achieve as one shown in this jsfiddle :http://jsfiddle.net/qaf4M/2/
I am using backbone.js and backbone.stick (http://nytimes.github.io/backbone.stickit/) to bind model to template.
I create view as follows with model as parameter
RegionManager.show(new app.myView({
model : new app.myModel(
{id: 1})
}));
MY model value is something like this:
{
"id":1, "name:"a" , "age":21
}
The view is as follows:
myView = Backbone.View.extend({
template: _.template( $("#template").html() ),
events: {
"click #save" : "update",
},
bindings: {
'#id': 'id',
'#name': 'name',
'#age': 'age'
},
initialize: function () {
if(this.model){
this.model.fetch();
},
render: function () {
this.$el.html( this.template );
this.stickit(); //used library http://nytimes.github.io/backbone.stickit/
Backbone.Validation.bind(this);
},
update: function() {
this.model.save (
{success: this.success_callback, error: this.error_callback});
},
success_callback: function (model, response) {
},
error_callback: function (model, response) {
alert('error.');
}
});
My template look like
<script type="text/template" id="template">
<form id="myForm " >
<fieldset>
<label>Name</label>
<input type="text" id="name" name="name" />
<label>Age</label>
<input type="text" id="age" name="age" />
<input type="hidden" id="id" name="id"/>
</fieldset>
<a id="save" disabled >Save Changes</a>
</form>
I am confused where should i bind event and how or what is proper way to know the user has chagne some value and accordingly disable button when there is no cahnge in form and enable when change has been made.
A simple solution would be to make your view listen to your model's changes:
initialize: function () {
if(this.model){
this.model.fetch({
success: function(model, resp) {
this.model._attributes = resp; // create a copy of the original attributes
this.listenTo(this.model, 'change', function() {
// when the model changes
// maybe write some function to compare both
if(_.isEqual(this.model._attributes, this.model.toJSON())) {
// disable
}
else {
// able
}
});
}
});
}
So, when the data comes back from the server, you create a copy, and then listen to your model's changes. If the new attributes equal the original, disable the button.

Categories