I am using the admin-dashboard template and made the following modification to the MainController:
routes: {
':node': {
before : 'checkSession',
action : 'onRouteChange'
}
},
Thus, when I change a route the before route will happen first, so the following method will first get called and then the routing will proceed onward:
checkSession : function() {
var args = Ext.Array.slice(arguments),
action = args[args.length - 1],
hash = window.location.hash;
// TODO: use hash to clear patient header when appropriate
if (hash.indexOf('#new-patient') > -1) {
console.log(hash);
}
action.resume();
},
This works splendidly. However, when I get the condition of hash.indexOf('#new-patient') > -1 I would like to clear a comboBox that I have defined in a view as:
bind: {
store: '{patients}'
},
reference: 'patientCombo',
This is from a view in the same scope as the above method from the viewController is, that is they are both in the hierarchy of the same viewModel. I am just not sure exactly how I can clear this from the above method. I just want to set the combo box back to no selected value (if one had been selected) and then update the bindings. Merci!
When I tried using Ext.ComponentQuery, I initially referenced the itemId, but the xtype was wrong (the combobox and displaytext, among other sundries are in a container). Since this is the only combobox in my app now, I just tried it as:
combo = Ext.ComponentQuery.query('combobox')[0]
if (combo){
combo.setValue('')
}
and, lo' and behold, it worked!
Related
I have two ViewController.
The first one fires an event if I select an item in a treepanel :
// treeController
onItemSelection: function(treeview, record) {
var me = this,
controller = me.getView().getController();
...
controller.fireEvent('myEvent', record);
}
The second one is listening to this event.
The controller is responsible for uploading a file to a specified url.
This url is set by the onMyEvent-function.
// uploadController
...
listen: {
controller: {
'*': {
myEvent: 'onMyEvent'
}
}
},
defaultUrl: 'foo/bar/{id}',
currentUrl: null,
onMyEvent: function(record) {
var me = this;
me.currentUrl = me.defaultUrl.replace('{id}', record.getId());
},
onUploadClick: function (form) {
var me = this;
if (form.isValid()) {
form.submit({
url: me.currentUrl,
...
});
}
},
...
What I want to achieve:
I select an item in the treepanel
-> the event is fired, the onMyEvent-function has been executed.
I click on the button to open the uploadView (the view which is connected to the controller). After that I'll click on the fileupload-button, select a file and click on the uploadbutton.
After the uploadbutton has been pressed, the controller should call the onUploadClick-function and use the previous placed url (currentUrl) for the upload.
The problems I'm facing:
Selecting an item in the treepanel fires the event, but the uploadController is not executing the onMyEvent-function.
When I open the uploadView first and select afterwards a node in the panel, the onMyEvent-function is executed.
When I use the second approach and try to upload the file, I get an error which tells me I haven't specifed the url (its null).
How can I accomplish the process without using the mentioned workaround for 1.?
Thanks in advance.
Your event myEvent is in UploadController. However, controller.fireEvent('myEvent', record); would try to find and fire it in TreeController.
Root cause of this issue is that controller = me.getView().getController(); is going to give you back this/instance of TreeController. When you do me.getView(),it gives you TreeView and me.getView().getController() is going to give you back an instance of TreeController and you need an instance of UploadController cause myEvent is an event of UploadController.
The reason you're able to fire the event when you open UploadView first is cause you're already in UploadController.
Hope that helps!
I’m trying to build this:
When I edit field on the left it should update the one on the right and vice-versa.
Editing a value in an input field causes the text cursor to jump at the end of it.
Typing "2" in the fahrenheit field gets replaced with 1.999999999999, as you can see on the screenshot. This happens because of the double conversion:
view’s Fº → model’s Cº → view’s Fº.
How can I avoid that?
Update:
I want to know the elegant way of dealing with two-way bindings in MVC frameworks such as Backbone.js.
MVC
var Temperature = Backbone.Model.extend({
defaults: {
celsius: 0
},
fahrenheit: function(value) {
if (typeof value == 'undefined') {
return this.c2f(this.get('celsius'));
}
value = parseFloat(value);
this.set('celsius', this.f2c(value));
},
c2f: function(c) {
return 9/5 * c + 32;
},
f2c: function(f) {
return 5/9 * (f - 32);
}
});
var TemperatureView = Backbone.View.extend({
el: document.body,
model: new Temperature(),
events: {
"input #celsius": "updateCelsius",
"input #fahrenheit": "updateFahrenheit"
},
initialize: function() {
this.listenTo(this.model, 'change:celsius', this.render);
this.render();
},
render: function() {
this.$('#celsius').val(this.model.get('celsius'));
this.$('#fahrenheit').val(this.model.fahrenheit());
},
updateCelsius: function(event) {
this.model.set('celsius', event.target.value);
},
updateFahrenheit: function(event) {
this.model.fahrenheit(event.target.value);
}
});
var temperatureView = new TemperatureView();
No MVC
celsius.oninput = function(e) {
fahrenheit.value = c2f(e.target.value)
}
fahrenheit.oninput = function(e) {
celsius.value = f2c(e.target.value)
}
function c2f(c) {
return 9/5 * parseFloat(c) + 32;
}
function f2c(f) {
return 5/9 * (f - 32);
}
Not only it fixes the problem, it’s also reduces the code 3.5⨉. Clearly I’m doing MVC wrong.
Here's my take on this; instead rendering the whole view on every change, in interactive views, use the view's jQuery or plain JS contexts just like your non-MVC example.
http://jsbin.com/fomugixe/1/edit
As the Backbone docs say:
"Two way data-binding" is avoided. While it certainly makes for a nifty demo, and works for the most basic CRUD, it doesn't tend to be terribly useful in your real-world app. Sometimes you want to update on every keypress, sometimes on blur, sometimes when the panel is closed, and sometimes when the "save" button is clicked.
Two methods come to mind. As Kinakuta mentioned you can do something like the following so you're math works on integers, instead of decimals:
temp = ((oldTemp * 100) * conversion stuff) / 100
Depending on how complex you want your app to be you can also use something like Backbone.ModelBinder. It automatically binds your view to your model so when one updates, the other updates automatically. You can then attach a converter function to the binding so when your value goes view -> model or model -> view it's run through the converter. I can elaborate more if that idea interests you.
Update: With a simple temp converter it's not surprising that Backbone requires 3.5x as much code. An MVC framework can reduce bloat in a large project, but for a small app it might be overkill. e.g. imagine using Backbone to display "Hello World".
As for your issue, how about only rendering the other input value when one is changed, instead of both? If F input changes, re-render value in C box. With ModelBinder I would do this by having two attributes in my model: tempF and tempC. When one is modified, I re-calculate the other and ModelBinder automatically displays it. Or you can go without MB and just listen for the change event.
set a variable at the view level where you hold the input field that started the conversion, so you don't call the conversion function on that field.
I'm implementing a simple (at least ,that was the goal) Kendo UI grid that displays two columns: one holding a checkbox, bound to a boolean, and one holding a display name for the item. The checkbox column has a simple template, and the change() event of the checkbox is handled so that the model in the datasource gets updated. I have verified this, and it works.
The data source has been configured for batch, and defines a transport for read and update. Both call a function that perform the ajax call. As I said before, the read function is handled as expected. However, the update function defined on the transport is not. The sync() on the datasource is triggered with a simple button whose click event is hooked to a function that calls datasource.sync() (or grid.saveChanges()).
transport: {
read: function(options) {
return loadStuff(options);
},
update: function (options) {
return updateStuff(options);
}
}
When debugging in the Kendo UI code, it looks like the models attribute on the ModelSet is always empty, and therefore the sync() decides that there's nothing to sync. Anyone got a clue what is happening here?
UPDATE:
Looks like something may be wrong when handling the checkbox check / uncheck. Apparently I should use something like
$('#divGrid').on('click', '.chkbx', function() {
var checked = $(this).is(':checked');
var grid = $('#divGrid').data().kendoGrid;
var dataItem = grid.dataItem($(this).closest('tr'));
dataItem.set("Selected", checked);
});
Unfortunately, it looks like the set() method is not defined on the data item. When debugging, it only contains the data, and no Model object having the set() method.
UPDATE 2:
Tried wrapping the data returned from the ajax call in a model defined with Model.define(). That seems to solve the issue of the model not being dirty, as the _modified property on the model returns true. However, the models array in the ModelSet remains empty. Is this a bug in Kendo UI, or am I going the wrong way?
You don't actually need to bind to click event on the checkboxes.
I´ve posted an example on using it in JSFiddle where you can see it running. This example displays in a grid two columns: first text (tick) and second boolean rendered as a checkbox (selected); the update is batch (so, it's pretty close to what you have).
Questions to keep in mind are:
For displaying the checkbox while not in edit mode, you should define a template, something like this. You might realize that the checkbox is in disabled state by default since you want to edit it as other fields (selecting the cell first). This also guarantees that the model is correctly updated:
{
field : "selected",
title : "Selected",
template: "<input type='checkbox' name='selected' #= selected ? 'checked' : '' # disabled/>"
}
Define in the model that this field is boolean:
schema : {
id : "id",
model: {
fields: {
symbol : { type: "string" },
selected: { type: "boolean" }
}
}
},
Define the transport.update function, something like:
transport: {
read : function (operation) {
// Your function for reading
},
update: function (operation) {
// Display modified data in an alert
alert("update" + JSON.stringify(operation.data.models, null, 4));
// Invoke updating function
// that should ends with an operation.success(the_new_data)
// In this example just say ok
operation.success(operation.data.models)
}
}
EDIT: If you want to be able to modify the checkbox state without having to enter in edit mode first, you should:
Remove the disabled from the template:
{
field : "selected",
title : "Selected",
template : "<input type='checkbox' name='selected' #= selected ? 'checked' : '' #/>"
},
Then bind the click event on checkboxes to the following handler function:
$("#stocks_tbl").on("click", "input:checkbox", function(ev) {
var dataItem = grid.dataItem($(this).closest('tr'));
dataItem.set("selected", this.checked);
});
Where #stocks_tbl is the id of the div that contains the grid. You might see it running here.
NOTE: It's important the on with the three parameters for making it live
I am using kendo ui treeview. I am loading the treeview dynamically from the database. But my issue is i am getting the expand error if there are no child's to display. How can i remove the expand arrow.
Regards,
Sri
There is a configuration field of the HierarchicalDataSource schema.model object called hasChildren you can add a boolean property to your model which indicates if the your model has items.
This way when the TreeView creates its elements it will check that property (or call the function - you could for example return if the items.leght is greater than zero) and if the returned value is false it wont create the expand arrow in front of the item.
Check this demo.
for an example, I have declared my function like this in my Kendo Ui TreeView :
var inline = new kendo.data.HierarchicalDataSource({
data: #Html.Raw(dataSource),
schema: {
model: {
children: "Children",
hasChildren: function(e) {
var test = e.Children.length;
return test > 0;
}
}
}
});
And for my, it works perfectly !
I'm having a problem with checkbox bindings not quite working with KnockoutJS 2.0. I have an array of objects. One of the properties of those objects is an array of different objects. In the child objects there are a few properties, one of which is a boolean. I build a list for each parent object and under each parent I show the children. For each list of children I have two views, a read only and an edit view. In the read only I have images that represent whether or not the item is checked based on the boolean property. This works and if I update the boolean value through the console, I'm seeing what I would expect--the image goes away or displays based on the value I assign. In the edit view, the images are replaced with a checkbox. I see the same behavior when I update the value through the console--it is checked when I expect it to be and not when I don't. The problem comes in when I check or uncheck the checkbox. Doing this doesn't change the underlying value the checkbox is bound to.
Here's the basic idea of my data.
[
{
"xxx": "yyy",
"xxx": "yyy",
...
"Displays": [
{
"xxx": "yyy",
...
"Excluded": false,
},
{
"xxx": "yyy",
...
"Excluded": true,
}
],
}
]
Here's the binding
<input type="checkbox" data-bind="checked: !Excluded()" />
the problem is that "checked" here is a bidirectional binding: the bound property needs to be read to generate the correct view, but needs also to be updated when you click on the checkbox. Contrast this to a binding like:
<span data-bind="text: 'your name is ' + name()"></span>
when the expression is only read, so you can use an expression (and you need to unwrap the observable).
So, you need to bind directly to the observable property, without "unwrapping" it adding '()', it will be done by knockout when needed, both for read and write:
<input type="checkbox" data-bind="checked: Excluded" />
See http://jsfiddle.net/saurus/usKwA/ for a simple example. Note how the checkbox labels are updated on change, showing that the model is updated and the rendering triggers correctly.
If you need to negate the value (so that the checkbox is checked when the value is false), you can add a writeable computed observable, as explained on http://knockoutjs.com/documentation/computedObservables.html section "Writeable computed observables", or you can negate the data in the viewmodel, doing it on the server just before sending the data, or on the client before populating the viewmodel.
hope this helps.
I know my answer is a bit late to the game here, but I had this problem today and this was the closest thread I could find related to the problem, and it doesn't seem to have an answer that solves it. So here's my solution.
Essentially, the issue is that knockout really wants your viewModel values to be a string, not a boolean, but this isn't always practical. So, I created a binding called "isChecked" which works strictly with booleans. Note: This will only work with observable properties.
ko.bindingHandlers.isChecked = {
getElementDeclaredValue: function (element) {
var declaredValue = element.getAttribute("value");
// If a value is provided, we presume it represents "true",
// unless its explicitly "false". If no value is provided, we
// presume that a checked state would equal "true".
return declaredValue && Boolean.isBool(declaredValue)
? Boolean.parse(declaredValue)
: true;
},
init: function (element, valueAccessor) {
var updateHandler = function () {
var declaredValue = ko.bindingHandlers.isChecked.getElementDeclaredValue(element);
var elementValue = element.checked ? declaredValue : !declaredValue;
var modelValue = valueAccessor();
var currentValue = ko.utils.unwrapObservable(modelValue);
if (elementValue === currentValue)
return;
if (ko.isObservable(modelValue)) {
modelValue(elementValue);
}
};
ko.utils.registerEventHandler(element, "click", updateHandler);
},
update: function (element, valueAccessor) {
var elementValue = ko.bindingHandlers.isChecked.getElementDeclaredValue(element);
element.checked = elementValue === ko.utils.unwrapObservable(valueAccessor());
}
};
The two Boolean methods ("parse" and "isBool") are defined as follows:
Boolean.isBool = function (value) {
return (/^(?:true|false)$/i).test(value);
};
Boolean.parse = function (value) {
return (/^true$/i).test(value);
};
I'll ignore any comments that say I shouldn't be modifying a built-in object prototype; I'll do as I damn well please ;-).
Usage is the same as the checked binding. The "value" attribute is optional, unless you want the checked state to represent false:
<input type="radio" id="rbNewClaim" name="ClaimType" value="false" data-bind="checked: isExistingClaim" />
Hope this helps someone.
I gave up trying to get this to work with the bool values and created an array of selected objects and handled it that way. It isn't the optimal solution, but I was tired of fighting this.