When developing a custom Kendo MVVM widget, passing a simple data-bound parameter seems fine, whether in a custom binding. IE:
<div data-bind="value: simpleParameter">This works fine</div>
<div data-bind="mybinding: simpleParameter">This also works fine</div>
I notice the css and events bindings can accept objects as parameters. I really want to accept objects as parameters too, but when I try, it throws an error:
<div data-role="mycomponent" data-bind="value: { prop: value }">This throws</div>
<div data-role="mycomponent" data-bind="mybinding: { prop: value }">This throws too</div>
In the case of the custom binding, it doesn't throw until I try accessing the value. I've tried it like...
var arg = this.bindings["mybinding"].get();
...and other variations, but nothing seems to work. Is it possible to accept objects like { prop: value, prop2: value2 } for custom Kendo UI widgets in their MVVM framework?
Your answer is in this article, Making Kendo UI Binders for Complex Types.
If you have tried to make a binder like this yourself, you have
probably run into issues. Kendo actually does not provide support for
these complex bind paths for custom binders.
Basically, Kendo UI expects your expressions to be a string representation of a variable or function name, not a complex object. What you have to do is call this.bindings.class.get() multiple times to retrieve the values you need.
To get these values for the get() function to read, you'll create a list of key/value pairs from the complex object in the binding's init() constructor method. Then, in your binding's refresh() method, you simply iterate over this list and call get().
Related
I have a kendo combobox.
In one of the method I am fetching value from the combobox.
Is it possible to mock the kendoComboBox using jasmine.
var $categoryComboBox = $('#Category').data('kendoComboBox');
var selectedCategory = categoryComboBox.dataItem($categoryComboBox.select());
My jasmine test case is something like
var combo = spyOn($.fn, "data").and.returnValue(dummyElement);
var selectedCat = spyOn($.fn, "select").and.returnValue("1");
var selectedItem = spyOn(combo, "dataItem").and.returnValue({ 'ID': '1', 'ClaimTypeCode': 'WW' });
I am not sure what should I specify as dummyElement for this to work.
Thanks
Sounds like you haven't structured your JavaScript for unit testing. You should separate the DOM from the code, so you can test the code independently of a DOM.
Take a look at KendoUI MVVM library, as this allows you to set up a view model (which knows nothing about the DOM), bind it to the HTML elements and Kendo widgets, leaving you free to test the view model easily.
The way you have your JavaScript set up now is going to make it extremely hard to unit test. The only thing I can think of is to separate the code that gets the value from the Kendo widget from the code that does something with that value, and then test the latter, passing in the value you want to test. Still not really the right way to structure it, but it would work for now.
Knockout has the default behavior of updating the associated model if you change your focus (e.g. by clicking outside the input control) after editing the value inside an input control, populated by a binding of type Value.
Here is the link to the official documentation page explanation, section Parameters:
http://knockoutjs.com/documentation/value-binding.html
Do you know a way to disable this default behavior ?
The reason behind this : Im using Models that can tell if their last update requires persistent backup by comparing the previous value to the new one.
I would like to listen to the key up event on my form inputs but if I do that, knockout triggers twice event (the default one + the key up) to update the Model and the second one is basically telling my Model to replace the value by the same value because it is already updated, which it translates to "there is no need to do persistent backup since the value didnt change".
I would gladly appreciate any help or suggestion, since Im stuck and can't find a way around :)
EDIT
Couldnt reproduce the error with bare backbone code. It seems as "super cool" said that valueUpdate should override the default Blur event that triggers when you use form controls with binding Value.
It may be a bug introduced by the library Knockback that I use to create the ViewModel.
Despite all this, just replacing the binding Value by the binding textInput did the trick. Thank you all.
Don't listen to the event, subscribe to updates, which won't fire unless the value is changed. Using the textInput binding will register every change to the value, even those done using menu items like cut and paste, when they happen.
Equivalently, you can use the value binding along with valueUpdate: 'input'
vm = {
myvar: ko.observable(),
updates: ko.observableArray()
};
vm.myvar.subscribe(function(newValue) {
vm.updates.push(newValue);
});
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input data-bind="textInput: myvar" />
<div data-bind="foreach: updates">
<div data-bind="text: $data"></div>
</div>
To avoid calling applyBindings multiple times on the same DOM element, I wrap my various viewmodels in an observable. then just change that observable to whatever view model i wanna see and BAM...that works.
until i do something like this:
<div data-bind="if:$data">
...some bindings in here
</div>
when i change view models, the bindings inside any "if:$data" blocks do not update.
here's a fiddle to really demonstrate this: http://jsfiddle.net/btrauma8/2TxME/
This would have worked properly prior to KO 2.2. In 2.2, we made if and ifnot more efficient by only re-rendering the section when the value actually changes between truthy/falsy.
There were many cases where people would bind against something like if: items().length and the entire section would be re-rendered everytime that an item was added.
In your case, you can overcome this pretty easily by just using the with binding instead of if. Since, you are binding against $data, it will not actually change the context and will give you the result that you are after.
Using ASP.NET MVC 3 and Razor, I have a strongly typed view against MyViewModel class. Within the view I have an AJAX form that consists of a group of radio buttons. Below it, I have a normal HTML form that collects data for MyViewModel. Depending on which radio button is selected in the AJAX form, I want to update the HTML form with one set of default values or another. In the AJAX form, I'm trying to post two pieces of data: 1) a value that represents the option chosen (basedon the radio button value parameter), and 2) the Model from the view. I want the controller action to update the model based on the option received, and then return a partial view with the updated model object as parameter. How do I do this? Here's the code for the AJAX form for my attempt:
#using (Ajax.BeginForm("MyAction", "MyController",
new AjaxOptions {
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "createForm"
}))
{
<div id="formOptions">
#foreach (Option op in Model.GetOptions()) {
<div class="editor-field">
#Html.RadioButton("option", op.OptionType, false, new { #id = op.ID, #name = op.ID, #title = #op.Description, #onfocus = "javascript:$(this).closest('form').find(':submit').first().click()" })
<label for="#op.ID">#op.Name</label>
</div>
}
</div>
#Html.Hidden("model", Model)
<input type="submit" value="Select" style="display:none;" />
}
My problem is that the model parameter in the HttPost action method is null. However, the option parameter seems to get passed correctly. I'm not sure if I'm using the Html.Hidden input in a way it's not supposed to be used or what the problem is. I can post more code if needed.
This is my first attempt at doing something like this, so after reading a lot of (seemingly) similar questions I still cannot decipher the solution for what I want to do. I see a lot of different things, like JSON encoding, using JQuery, etc., but I'm not sure if I need those things, or if I can accomplish this using MVC features (I'd rather not recode things that are already built into MVC 3). If anyone can point me in the right direction or possibly give a little code example, it would be appreciated. And, given what my end goal is, if there's a better way to asynchronously update a form based on option controls, I'd be very interested to hear about it. Thanks!
EDIT:
I also noticed that the request using HttpPost does not make it to the controller, but a HttpGet does. Anyone out there? This is driving me nuts!
ADDED CONTROLLER METHOD:
public PartialViewResult CreateForm(OptionType opType, MyViewModel model) {
model.ApplyOptionValues(opType);
return PartialView("_CreateForm", model);
}
I would not post the entire model back to the controller which you are attempting to do with #Html.Hidden("model", Model) simply place the specific items you need in the form with names/types that match your controller. You can use the selected radio button's value as well as a hidden input's values to pass identifying information to the controller and perform whatever logic you need there.
That being said, I think the best solution going forward would be to use some javascript framework like JQuery to handle all AJAX requests. Asp.net MVC makes it really easy to do simple operations with the built in pieces, but once you need to perform more complicated operations, it definitely falls short. You end up putting in more effort to work within the limitations than if you just used the correct tool (JQuery).
Make sure that you annotate your POST action methods with [HttpPost] to differentiate from GET methods.
Also use a detailed web debugger to examine exactly what is being sent to your application. I like Fiddler, which is extremely popular.
http://www.fiddler2.com/fiddler2/
I would agree with Mattbo: posting the whole model round in a circle is unnecessary overhead. You don't say why you are but I suspect it's so you can compare 'old' and 'new' values. Given the model originates in the controller, you could include a unique identifier for the model (e.g. GUID) in the ViewModel, put that in a hidden field to include in your POST data, then on the return POST your 'new' data will be auto mapped to the strongly typed ViewModel. You can then re-get the original model and do whatever you need to with them both.
Dealing with the AJAX form is a separate issue/form then: you have your radio buttons which fill out default values in the (view model) form (including a hidden field to record which radio was selected), the user fills out the other data and the whole of the (non ajax) form gets posted to the MyController.MyAction method and the default binders will automatically map the form values to the MyViewModel, if they follow the right naming convention. So the AJAX has nothing to do with the form that is actually posted. Alternatively you could do the whole thing with AJAX as Mattbo also suggests.
[Aside] Forgive me if you already know but you can use the razor Html helpers to create your fields like:
#Html.EditorForModel()
#Html.EditorFor(model => model.[field name])
In the Controller you would create the actions like:
public ActionResult MyAction()
{
MyViewModel
}
[HttpPost]
public ActionResult MyAction(MyViewModel myModel)
In respose to Infragile's request in another thread, I am asking this as a separate question rather than a followup.
Here is the problem I am attempting to address:
I'm migrating from JSF1.2 to JSF2. Everything worked fine in JSF1.2.
I have rewritten a critical item to be a composite component which is basically a panel created in my backing bean by adding components in code.
In particular, I have h:inputText and h:selectOneMenu components that I create in code along with an "Apply" h:commandButton.
The "Apply" button has an action listener that checks for the values in the h:inputText and h:selectOneMenu components. All this works fine, but when I fetch the values in the h:inputText or h:selectOneMenu components I get the original values, not the new values that were entered by the user. Like I said, this worked fine in JSF1.2 (i got the new values), but not in JSF2 for some reason.
I have tried several things to get around this that haven't worked, so I figured I would add ajax behavior to the h:inputText and h:selectOneMenu items and when the values in these components change, I could call another backing bean listener for the ajax behavior to fetch the new values.
I am trying to add ajax behavior to a component I create in code (not bound to a page component). I can create the component with no problem. However, the problem that I am having is how to add the ajax behavior to the component.
Could someone post sample code to add an ajax behavior for a value change or blur event? Here is the code I use to create the component in code - how would I need to modify it to add the ajax behavior?
hpg = new HtmlPanelGrid();
children = hpg.getChildren();
children.clear();
....
input = new HtmlInputText();
....
children.add(input);
What code would I have to add to replace the "add ajax behavior here" line, and what would the arguement for the listener method be (arguement for the method to replace the ????? below)?
public void myAjaxListener(?????) { ...... {
I have been trying to get a handle on this for some time now. I feel that I am pretty close, but don't know the syntax I need. I can provide more information on how I am fetching the component Ids and searching for the values in my action listener if that will help.
Thanks
This is how you can add dynamically AjaxBehaviorListener to yor component:
...
HtmlInputText inpuText = new HtmlInputText();
AjaxBehavior blurBehavior = new AjaxBehavior();
blurBehavior.addAjaxBehaviorListener(new BlurListener());
blurBehavior.setTransient(true);
inputText.addClientBehavior("blur", blurBehavior)
...
public class BlurListener implements AjaxBehaviorListener {
public BlurListener() {
}
#Override
public void processAjaxBehavior(AjaxBehaviorEvent event) {
// do your job
HtmlInputText inputText = event.getComponent(); // your input text component
...
}
}
"blur" represents event when this listener will be triggered. Remember that JSF Component must support this event, otherwise it won't work.
(Here you can see under covers and how to build custom AJAX component http://weblogs.java.net/blog/driscoll/archive/2009/10/09/jsf-2-custom-java-components-and-ajax-behaviors?force=670 )
However in your case I think problem is that buttons ActionListener is triggered before actual component values are submited. You can solve it by moving your ActionListener logic to button action, by aformentioned AJAX, maybe by findinng actual values in UIComponents (HtmlInputText, UISelectOne), not sure but immediate attribute can also influence it.