Multiple Knockout binding with function and variable - javascript

Multiple Knockout binding.
I want to use just one apply binding instead of two apply binding. One is variable other is function. i am using requireJS also.
HTML:
<button id= "Hand" name="Hand"
data-bind="click: Handler2">
</button>
KnockoutJS
function (ko, $)
{
function DM1ViewModel() {
var self = this;
self.bId = ko.observable('TEST456');
}
$('#hide').hide();
var DMD2 = {
Handler2: function() {
window.location='http:www.google.com';
}
};
ko.applyBindings(new DM1ViewModel(), document.getElementById('Container'));
ko.applyBindings(DMD2);
});

As it stands, there's really no reason to applyBindings on your DMD2 objects since there aren't any observables there.
However, to answer your question more generally, you have two options:
Call applyBindings for DMD2 against an element that doesn't contain your Container element, and isn't already contained within your Container element.
Javascript:
// DM1ViewModel is the same
var DMD2ViewModel = function() {
this.Handler2 = function() {
window.location='http:www.google.com';
};
}
ko.applyBindings(new DM1ViewModel(), document.getElementById('DM1Container'));
ko.applyBindings(new DMD2ViewModel(), document.getElementById('DMD2Container'));
HTML
<div id="Container">
<div id="DM1Container">
<h2 data-bind="text: bId"></h2>
</div>
<div id="DMD2Container">
<h2 data-bind="click: Handler2">Click me</h2>
</div>
</div>
Make one parent view model that has each of your existing view models as observables and the use the with binding
Javascript:
var PageViewModel = function(){
this.dm1 = ko.observable(new DM1ViewModel());
this.dm2 = ko.observable(DMD2); // currently isn't a function, so can't call new
}
ko.applyBindings(new PageViewModel(), document.getElementById('Container'));
In your html:
<div id="Container">
<div data-bind="with: dm1">
<h2 data-bind="text: bId"></h2>
</div>
<div data-bind="with: dm2">
<h2 data-bind="click: Handler2">Click me</h2>
</div>
</div>

Related

Knockout js disable button if parent hasClass

Is it possible to disable a button inside of a child div if $("#parent").hasClass("bar"); without putting a data-bind... attribute on the actual button? Below is my code. I sense this is possible but I am not sure I am approaching it right:
The HTML:
<div id="parent" class="">
<div class='active'>
<button>Button 1</button>
</div>
<div>
The JS
function foo(){
var self = this;
self.parent = ko.pureComputed(function(){
return $('#parent').hasClass('bar');
});
if(self.parent){
$('.active button').attr("disabled",true);
}
};
ko.applyBindings(foo);
The reason for this approach is that there are going to be many, many child divs but only one with the active class and I am concerned about binding all of them if I don't have to. Many thanks,
how about just using a subscription and stealing monkey_dev1300 jquery.
run snippet below. and change the class from foo to bar.
function viewModel(){
var self = this;
this.parentCss = ko.observable('foo');
}
var vm = new viewModel()
ko.applyBindings(vm);
vm.parentCss.subscribe(function(newValue) {
if(newValue === 'bar')
{ $('.active button').attr("disabled",true); }
else
{{ $('.active button').attr("disabled",false); }}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>
change class: <input data-bind="value: parentCss"/>
</p>
<div id="parent" data-bind="css: parentCss"
<div class='active'>
<button >Button 1</button>
</div>
<div class='active'>
<button >Button 2</button>
</div>
<div class='active'>
<button >Button 3</button>
</div>
<div>
If you want to "disable" a button you can use this with JQuery and css:
$('button').css("pointer-events", "none");
This will stop the button from triggering click events.
Likewise you can 'enable' it with
$('button').css("pointer-events", "auto");

Proper way to execute a script tag in a Knockout HTML template

I have the simple html page, where simple ul list defined with following viewmodel for it:
<div class="row">
<div class="col-md-6">
<button class="btn btn-link" data-bind="click: addItem">Add item</button>
<ul data-bind="foreach: listItems">
<li>
<p data-bind="text: itemText"></p>
<script>
$(document)
.ready(function() {
console.log("new li has added");
});
</script>
</li>
</ul>
</div>
<div class="col-md-6">
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
</div>
</div>
<script>
function ItemViewModel(text) {
var self = this;
self.itemText = ko.observable(text || "");
}
function ListViewModel() {
var self = this;
self.listItems = ko.observableArray([]);
self.addItem = function () {
self.listItems.push(new ItemViewModel("new item: " + self.listItems().length));
};
}
ko.applyBindings(new ListViewModel());
</script>
My fiddle: https://jsfiddle.net/1c3prhhv/
Adding items to list work perfectly, though script tag in list item template doesn't work. Each time when item adds to list, I need to execute all JavaScript code in corresponding script tag.
How to properly add items to Knockout's observable array with executing JavaScript code in them?

unbind ng-click dynamically from element : angularjs

i have an element which have ng-click event and on clicking it adds a div that works fine. what i want is to remove ng-click after adding the div .
one way is to use ng-if
<div ng-click="addDiv()" ng-if="!divAdded" >
<span>i add a div</span>
</div>
<div class="disabled" ng-if="divAdded" >
<span>i add a div</span>
</div>
for this i have to add multiple div for single element that works on and off.
is there any way to unbind click event like we do in jquery dynamically?
any help will be appreciated
You can also do this:
<div ng-click="divAdded || addDiv()" >
<span>i add a div</span>
</div>
This will prevent ng-click from calling addDiv() if divAdded is true
Put that logic into the controller, not into the view
Controller:
(function(){
function divAddController() {
var self = this;
self.divAdded = false;
self.addDiv = function() {
if(!divAdded) {
//Add div here
self.divAdded = true;
}
}
}
angular.module("example")
.controller("divAddController", divAddController);
})();
View:
<div ng-controller="divAddController as divAdder">
<div ng-click="divAdder.addDiv()" ng-class="{disabled: divAdder.divAdded}">
<span>i add a div</span>
</div>
</div>
You can do it in a more easy way like this:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope) {
$scope.showDiv = false;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<button ng-click="showDiv = true;">I show the div</button>
<div ng-if="showDiv">I am visible!</div>
</div>

Angular event 'ng-click' binding issue

I am having problem with angular ng-Click.
My Controller
var ParentController = function ( ) {
this.MyEvent = function () {
alert('foo-bar');
};
this.AddHTML= function () {
$("#ButtonSec").html('<input type='button' ng-click='Parent.MyEvent()' value='inner button'/>');
};
};
angular.module('myApp', []).controller('ParentController', ParentController);
HTML - 1 (Works as expected button ng-click binds to 'inner button' as expected):
<div ng-app='testComponent'>
<div id="content" ng-controller="ParentController as Parent">
<div id="ButtonSec">
<input type='button' ng-click='Parent.MyEvent()' value='inner button'/>
</div>
</div>
</div>
HTML-2 (Not working):When rendering html using Add HTML button. Event not binding to inner button as it should (important thing I can't use $scope as per client requirement)
<div ng-app='testComponent'>
<div id="content" ng-controller="ParentController as Parent">
<div id="ButtonSec">
</div>
<input type='button' ng-click='Parent.AddHTML()' value='Add HTML'/>
</div>
</div>
I'd suggest you to use ng-if directive which will add or remove html on the Expression which we will provide to it. To showing hiding that div you need to maintain one variable inside your controller context that will be responsible for showing that div on html.
Html
<div ng-app='testComponent'>
<div id="content" ng-controller="ParentController as Parent">
<div ng-if="Parent.showContent" id="ButtonSec">
<input type='button' ng-click='Parent.MyEvent()' value='inner button'/>
</div>
<input type='button' ng-click='Parent.showContent = true' value='Add HTML'/>
</div>
</div>
Not sure why you don't want to use $scope because angular manage $scope eventually internally. This is hack way using $rootScope
var ParentController = function ($compile,$rootScope ) {
this.MyEvent = function () {
alert('foo-bar');
};
this.AddHTML= function () {
$("#ButtonSec").html($compile("<input type='button' ng-click='Parent.MyEvent()' value='inner button'/>")($rootScope.$$childHead));
};
};

Knockout nested bindings

I'm having a problem using knockout and a form and getting bindings to apply without throwing errors.
I would like to split the logic for the form into several view models but I'm getting errors with bindings in bars and foos not being found when I attempt to bind foobar
I've tried to display this in the example below.
Is there a way to achieve the desired behaviour? Is there a way to say combine all the bindings from the three view models then assign them to foobar?
bars_observable is a ko.observable created in the contructor of barViewModel.
<div id="foobar">
<form data-bind="with: newFooBar, submit: submitFooBar">
<section id="bars">
<div data-bind="text: bars_observable"></div>
</section>
<section id="foos">
foo stuff
</section>
</form>
</div>
<script type="text/javascript">
$(function () {
var foobarViewModel, fooViewModel, barViewModel;
foobarViewModel = new ViewModels.FoobarViewModel({
fooViewModel: new ViewModels.FooViewModel({}),
barViewModel: new ViewModels.BarViewModel({})
});
ko.applyBindings(foobarViewModel, document.getElementById("foobar"));
});
</script>
The error would be
"Uncaught Error: Unable to parse bindings. Message: ReferenceError: bars_observable is not defined;"
I would recommend to put fooViewModel and barViewModel objects into FoobarViewModel. In this case you have to call ko.applyBindings only once.
<div id="foobar">
<form data-bind="with: newFooBar, submit: submitFooBar">
<section id="bars" data-bind="with: barViewModel">
<div data-bind="text: bars_observable"></div>
</section>
<section id="foos" data-bind="with: forViewModel">
foo stuff
</section>
</form>
</div>
<script type="text/javascript">
$(function () {
var foobarViewModel = new ViewModels.FoobarViewModel({});
ko.applyBindings(foobarViewModel, document.getElementById("foobar"));
});
function ViewModels.FoobarViewModel() {
var self = this;
self.fooViewModel = new ViewModels.FooViewModel({});
self.barViewModel = new ViewModels.BarViewModel({});
...
}
</script>
If you are writing a modular system, creating a top level view model may not be possible. In knockout 2.0 you can tell knockout to stop parsing bindings at a certain point. Then you can call applyBindings again for the container. Here is an article which explains how to do it.
http://www.knockmeout.net/2012/05/quick-tip-skip-binding.html

Categories