Add new properties to Knockout viewmodel after ko.applyBindings is called - javascript

In a (webforms) page I have a button that opens a jqueryui dialogue which is loaded dynamically.
The problem is that I want this dialogue to be master of its own knockout view model but the view model is already set in the main page.
I suppose it is not possible to add new properties to the view model after ko.applyBindings is called.
Instead I should be looking into another design. But which?
Applying bindings to different parts of the DOM would require me to some big redesigns I hope to avoid right now.
Having all the dialoge bindings as a list of key-values is possible but not very elegant IMHO. The main page would then only have to add a vm.dialogueKeyvalueCollection.
My present, possible, solution is to have the main form add the dialogue's properties vm.dialogue.userName() vm.dialogue.searchResult() but then my html controls won't bind as they are created after applyBindings is called. The present solution for this is to call ApplyBindings again like so: ko.applyBindings(vm, $('#dialog-form')[0]); for the added HTML. I was in the belief (and still somewhat am) that to call applyBindings for different DOM elements one must not be nested inside another. Binding to dynamic HTML is commented here and jsfiddled here.
?

I do a lot of composition with nested view models, often for the purpose of creating dialogues modals. See here for a full-fledged answer.
It might be simpler to try and get away with just using the with binding, though. You could create a dialogueViewmodel observable property on your viewmodel.
Just fill it with one or more observable keys when you're ready to show the dialogue, such as
this.dialogueViewmodel({
markup: ko.observable("<h1>Kittens!</h1>")
});
and wrap it in a with binding:
<!-- ko with: dialogueViewmodel -->
<div id="dialog" title="Basic dialog" data-bind="html: markup">
</div>
<!-- /ko -->
As long as dialogueViewmodel is null, nothing gets bound and rendered. This only happens when you add your dialogue data - no need to fiddle with applyBindings again.
You will probably have to write your own binding to interface with jQueryUI.dialogue, though.
Third option: I have written a modal library that comes with a Knockout binding out of the box. Here's a JSfiddle demo. If you're not set on jQueryUI, that might be an alternative; while the documentation is not perfect, I'd be happy to help you any way I can and fix the docs along the way.

Can you ko.applyBindingsToNode function to bind the appended html.
ko.applyBindingsToNode(appendedelement,{ binding options})
Hope this will help you.

Related

Where to implement ng-click functions, controller or directive?

I'm a beginner in AngularJS, I understand most of the mechanics but I'm still grasping the "culture".
I'd like have clean separation between my HTML, DOM, data and communications.
My impression of a controller is a module that implements a "data" model, but is void of UI semantics (i.e. DOM manipulation).
However in my HTML, if I use an ng-click it is the controller's scope that is accessed for the click function implementation, which more then likely will need to call back into the DOM.
So where should I implement my click functions if I do not want DOM manipulation in my controller? Are DIRECTIVES the universal answer to this?
Suppose I have 2 controls on a page that need to interact with each other, should I create a directive on the parent of those controls parent that implements the click functions of both child controls? Or perhaps create a directive for each control and possibly pass the ID of the other control as an attribute? OR maybe a directive for the parent AND children?
--------- UPDATE 1 -----------
The following HTML is a simplified and contrived example that [hopefully] illustrates my question.
<div id="searchComponent">
<input id="txtSearchText" ng-keyup="..."/>
<input name="Go" id="btnDoSearch" ng-click="..."></input>
<div id="autoCompleteResults"></div>
<div id="fullResults"></div>
</div>
As the user types in the txtSearchText, the autoCompleteResults is populated, factoring in the usual minimum characters and timouts.
When the user presses or clicks the btnDoSearch, the autoCompleteResults is cleared/hidden and the fullResults is populated.
Finally, if the user begins typing new txtSearchText, the fullResults would be cleared/hidden and the autoCompleteResults is again seen with results.
Any guidance would be appreciated!
So where should I implement my click functions if I do not want DOM manipulation in my controller? Are DIRECTIVES the universal answer to this?
DOM manipulations, in my opinion, means something like document.querySelector(), addCliss, etc. ng-click is the event, which is supposed to deal with some business logic. Put it in the controller is fine.
Of course, directive is your another choice. directive is usually used to extract some reuseable components, such as modal, across different pages. If you repeat some code in different controllers, consider extracting them to directives or service.
Suppose I have 2 controls on a page that need to interact with each other,...
In short: use service, which is designed for that scenarios.
The general philosophy is to reference the DOM explicitly as little as possible. Most (if not all) things you want to do can be done by binding an aspect of you HTML element to a property on $scope, and manipulating that property. So you never have to do some like "Change the class of <span id="foo"> to red now that isRed is true". Instead you would have <span ng-class="{ red: isRed }>". So if you have two click handlers that share information, it's perfectly valid to have them change some common variable in your controller, and have state of the UI accordingly with DOM bindings. Directives are used more for reusing DOM elements, or when you do have to explicitly refer to DOM elements, i.e. adjusting the scroll properties of a div. You could use a directive to add the same click handler to many elements for example. Services can be used to share information, although if both of the controls belong to the same scope there's less of a reason to do that.

How can I put content from my index.html into my view.html?

I have something like this plunker. I would like my view to get populated with the mapId that gets passed into the directive. Then I would like to show that view in place of "This is some content".
First how can I pass the mapId into the view and secondly how can I then show that view in the lightbox div?
I know this is kinda vague but I'm new to angular so I don't know what other information is needed here.
You're not going to be able to use the view.html file with the current lighbox code. It would need to be heavily modify to make use of template files and isolate scopes. However, you can use the current code to achieve the same thing with perhaps the addition of a controller to modify the scope.
I've modified the index.html in the plunker so that it displays the mapId value.
Let's go over what angular-lightbox is actually doing:
By returning just a function, the directive is going through the whole compile process and then using the returned function as the linker. The linker then goes on to (depending on the options) add an overlay (the opaque dark background of the lightbox) to the DOM & then add the lightbox active class to div#lightbox. This div is already in the DOM, but hidden due to the CSS, and has been already compiled & rendered by AngularJS so it can't really be changed other than through two-way data binding at the same or child scope level.
What my changes did:
I added a bound scope variable to div#lightbox called mapId and added an ng-click to the buttons that sets the value of mapId to 1, 2, or 3. So when you click on the button, div#lightbox is revealed & the value of the new value of mapId is shown.
Given that the above is probably not what you want to accomplish...
Let's talk about how to go about doing that
First you will need to load view.html into the directive somehow. Either by just having the view.html contents be a string inside the directive or use $templateCache.
You will then need to $compile the HTML from view.html, passing in a new scope that contains the values you want from options, and then append it to div#lightbox.
I would use a modal from Angular-UI bootstrap http://angular-ui.github.io/bootstrap/, and adapt it for my case. I think this is a good starting point.

Kendo UI: Get TextBox Value on Button Click

I am having a form, which comprises of several textboxes and one button.
I am using the Kendo UI MVVM format. How shall I get the value of each textbox and store it in an object on click of the button?
Will I have to use normal jQuery in order to get the values or is there some other way of getting the values from each of them?
Thanks
Hardik
Please take a look at these documentation pages:
http://demos.kendoui.com/web/mvvm/index.html
http://docs.kendoui.com/getting-started/framework/mvvm/observableobject
http://docs.kendoui.com/tutorials/mvvm-in-kendo-ui
These pages contain answers to most of the questions you'll have concerning Kendo UI MVVM. It would be silly and presumptuous of me to think that I could explain it better than the qualified and hard working individuals at Telerik that have so painstakingly compiled these documentation pages.
The gist of it is that you need to create an instance of the kendo.data.ObservableObject that has properties for the values you are working with. This is your view-model. Then in your markup for your text boxes, include values for the data-bind attribute that reference the properties in your observable object. Create a function in your view-model to handle the button's click event. Put a data-bind attribute in your button that binds the click event to your function. Finally, call kendo.bind(<element>, <observable object>), and that will connect the wires from your markup to your view-model object.
In your click event-handler, you can take the values of the view-model, and insert them into the object you need. You should not need to use "normal jQuery" for anything besides referencing the element to call bind on.
Quickly you can retrieve the value this way using JQuery:
$('#yourTextBoxID').data('kendoMaskedTextBox').value();
you can use this code:
$('#yourTextBoxID').val();

How to make all buttons(even dynamically created) in an application follow jquery button widget without calling .button() multiple times

I am new to stack overflow and this is my first question. Pardon me for any mistakes.
This question is more generic but i tried to search for an answer but could not find it.
Say i have a page and i am using jquery ui button() widget for all the button. What happens is i have a specific class defined for all the buttons on my page. So i can just specify $('.myButtonClass').button(); but whenever i render partial views which has button again i have to do the same thing in the partial views. Is there any way i can globally specify a transition for button or any element for that matter.
Here is a sample Fiddle which adds buttons on click. But the added buttons are not transitions as button widgets(I do not want to use clone).
http://jsfiddle.net/wjxn8/
$('.clsTest').button().click(function(){
$(this).after('<input type="button" value="Added" class="clsTest"/>');
});
Is this possible without:-
1) Adding the css classes for a button widget manually for all the buttons created.
2) Tracking DOM Changes using Javascript and perform transitions for all the button elements.
Thanks for your help!!!
Since you were looking for something else, why not trigger a custom event when you load partials or whatever:
$('.clsTest').button().click(function(){
$(this).after('<input type="button" value="Added" class="clsTest"/>').trigger('addButtonUI');
});
$(document).bind('addButtonUI',function(){
$('.clsTest').button();
});
http://jsfiddle.net/wJXN8/3/
If you trigger your event and have the document listening for it, then you can do whatever you would like. I could have put in there the ability to add more buttons as well, but this should get the point across.
What you are asking for, some event when a button is added.... you would need to come up with that yourself and trigger it when a button is added. There is this: How to detect new element creation in jQuery? which talks about a specific event that is triggered when new elements are added to the DOM. Haven't tested it, and it looks like it may not work on IE.
I'm not a huge fan of this, but you could poll for new buttons. Check out my fork of your fiddle (that sounds funny):
http://jsfiddle.net/lbstr/Hq97H/
Using your example, this would look like:
setInterval(function(){
$('.clsTest').not('.ui-button').button();
}, 1000);
As I said, I'm not a huge fan of this. I understand the desire for something like $.live here, but I still think its better to initialize your new content when you add it. If you are making an ajax call for new content, just initialize it when you add it to the DOM.
My silly polling code and $.live (which is now deprecated) might be convenient, but they perform terribly. Just my two cents. You know your code better than I do!

What is the best practice for presenting a modal view and binding events to it?

In a very common scenario, I have an HTML page with an "Add" button that opens a modal dialog (through Facebox) and asks the user to select an item from the list that appears in it.
The modal dialog gets its HTML snippet from the server asynchronously. I want this snippet to be reusable in many parts of my application so it shouldn't assume that I am using Facebox to load it. The only thing it should do is to trigger the item-selected event whenever the user selects an item in it. But since the snippet is loaded asynchronously, I cannot use $(document).ready. That is, I cannot trigger the event like this:
$(document).ready(function() {
$(".item").click(function() {
$(".items-modal-dialog").trigger("item-selected", this);
});
});
Also, I don't really like using the items-modal-dialog class to identify the enclosing DOM element.
I came up with some solutions to this, and I would like to know if there is some superior pattern that I am missing, because I think this is a very common problem.
Put the script after all the HTML so I am sure that the snippet DOM is loaded (I think this is a bad practice)
Creating a JavaScript function that loads the snippet with Facebox and then binds the events. This way I assume that I am using Facebox and also have to create a function for every type of modal dialog that I create. The only positive side I see in this is that I can create the items-modal-dialog DIV programmatically so I don't have to use a class to identify it.
Using jQuery live to bind the events.
Using an iframe and $(document).ready.
Any suggestions would be greatly appreciated.
Using jQuery's live or delegate function would be the best solution in my opinion.

Categories