I am trying working with knockout.js - mouseover and mouseout. I am bit new with Knockout. What I have done below:
<h2 id="popup" data-bind="event: { mouseover: PK.showdiv, mouseout: PK.hidediv }">
Search
</h2>
and I have my script block like below:
#section Javascript
{
<script type="text/javascript">
$(function () {
PK.showdiv = function () {
alert("Showed");
};
PK.hidedivOver = function () {
alert("Hidden");
};
})
This works fine if I use normal JavaScript call with "onmouseover" or "onmouseout". But the knockout.js call like data-bind with events is not working.
I am using MVC with Razor view.
I've created some example in jsFiddle Click here to see an example
So, in general I've created two functions on my ViewModel with names 'showdiv' and 'hidediv'
Javascript Code:
Note: we should apply bindings for our viewModel in the bottom of our js code (calling ko.applyBindings(new viewModel()); )
var viewModel = function(data) {
var self = this;
self.action = ko.observable("Hidden");
self.showdiv = function () {
//alert('Showed');
self.action("Showed");
$('#mySpan').addClass('redColor');
};
self.hidediv = function () {
//alert('Hidden');
self.action("Hidden");
$('#mySpan').removeClass('redColor');
};
};
ko.applyBindings(new viewModel());
HTML Code:
<div data-bind="event: { mouseover: showdiv, mouseout: hidediv }">Search</div>
<span id="mySpan" data-bind="text: action"></span>
CSS Code
div{
width: 100px;
height: 100px;
border: 1px solid #222;
}
span{
margin: 20px;
}
.redColor{
color: red;
}
START EDIT
Sorry, forgot to mention your mistakes:
1. You didn't initialize PK as
var PK = this;
2. In HTML code you don't need to call you functions using PK, just put the function's names:
<h2 id="popup" data-bind="event: { mouseover: showdiv, mouseout: hidediv }">
Search
</h2>
3. In javasript code you have incorrect function name like 'hidedivOver', so you should rename this function to 'hidediv' or you can rename function 'hidediv' in HTML Code to 'hidedivOver'
4. You didn't create view model and didn't apply it to knockout
END EDIT
Does it answer your question?
Thanks.
It seems to me that your didn't call applyBindings function:
ko.applyBindings(PK);
Also I don't see how you initialize PK object.
Make sure that you call applyBindings when page is ready. For this you can put it at the botton of the page or inside $(document).ready.
Related
I am using the FoundationPress theme (Wordpress Theme with the Foundation 6 from Zurb framework), and i'd like to ajaxify it. (using Ajaxify Wordpress Site plugin).
Now my problem is that most of the javascript that's on my website isn't working after an ajax load.
I have found that this is because most of the javascript in the foundation.js file is executed on document.ready, and that this event is not being triggered when loading a page with ajax.
I understand that it is not possible to trigger the document.ready event after page load. And after seeing multiple threads here, it appears the only solution is to create a new function with the code that's needed on document.ready and ajaxComplete.
BUT, Foundation has a lot of javascript files, and most of it is above my level of understanding. Is there any way to create a function that would automate this ?
EDIT I tried this. I need to pass jQuery as an argument or the code inside initialiseSticky will not work. It works for document.ready but not for ajaxComplete, any idea ?
jQuery(function($) {
console.log('document ready- sticky');
initialiseSticky($);
});
$(document).ajaxComplete(function ($) {
console.log('ajax complete- sticky');
initialiseSticky($);
}(jQuery));
function initialiseSticky($) {
//my code
}
Not sure about foundation.js but if you can make a variable, FooBar for example, assign the function() in $(document).ready() to that variable, and then on ajaxComplete call the variable/function again to "re-trigger" it, like below:
jsFiddle
var res = $('#result'),
bg = $('#bg-div'),
btn = $('#btnTest'),
i = 0, // just for demo to illustrate that it is changing
FooBar;
$(document).ready(FooBar = function() {
bg.delay(200).fadeIn(2000);
console.log('document is ready ' + i++);
});
// simulate ajaxComplete
btn.on('click', function() {
res.text('just dummy text here ' + i);
bg.fadeOut(500);
FooBar();
});
body { margin: 0; padding: 0 }
#bg-div { background-color: orange; width: 100%; height: 100%; position: fixed; z-index: -1; display: none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="bg-div"></div>
<button id="btnTest">Click Me</button>
<div id="result"></div>
I have this code:
document.getElementById('auth-button').addEventListener('click', authorize);
When my page load I want to trigger that without clicking the button.
This is my view
When authorized button clicked this is the output
I want to auto click that button when my page load.
You can use addEventListener to the DOMContentLoaded event:
document.addEventListener('DOMContentLoaded', function() {
authButton.click();
}, false);
Full example:
https://jsfiddle.net/7q0gxehk/1/
you can use Document ready in jQuery, try this..
$( document ).ready(function() {
authorize();
});
or this in javaScript..
window.onload = authorize;
NOTE: The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images, scripts, links and sub-frames have finished loading.
You could call the function authorize() on load of page using below code :
document.addEventListener("DOMContentLoaded", function(event) {
authorize();
});
You can register authorize as handler to be called when the page is fully loaded:
$(document).ready(authorize);
This requires jQuery. The same can be achieved without jQuery this way:
window.addEventListener('load', authorize);
It would be easier to tigger authorize function directly on page load using window.onload which is better than document.onload, see window.onload vs document.onload
window.onload = authorize;
However, if you are thinking about triggering click programmatically which is not suggested since it won't work properly across browsers e.g. Safari doesn't work at all
None of the other answers offered thus far seem to take something into account - that the registered handler may in fact need to be aware of it's place in the DOM.
We could for instance, have a number of buttons that all call the same handler, with that handler manipulating the surrounding DOM. Simply calling authorize when the page loads will not be sufficient.
I've chosen to use DIVs instead of BUTTONs to demonstrate that the .click() method still works.
A far better way is to actually click the button, using javascript.
#1 Not working
function byId(id){return document.getElementById(id)}
function allByClass(clss){return document.getElementsByClassName(clss)}
// useful for HtmlCollection, NodeList, String types
function forEach(array, callback, scope){for (var i=0,n=array.length; i<n; i++)callback.call(scope, array[i], i, array);} // passes back stuff we need
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
forEach(allByClass('mBtn'), addHandler);
function addHandler(elem)
{
elem.addEventListener('click', authorize, false);
}
alert('hit a okay to call authorize');
authorize(); // wont return from this call, since authorize relies on a valid 'this' value
}
function authorize(evt)
{
this.classList.add('clicked');
this.textContent = 'clicked';
}
.mBtn
{
border: solid 1px #555;
border-radius: 2px;
display: inline-block;
}
.clicked
{
color: #dddddd;
pointer-events: none;
}
<div class='mBtn'>Try me</div><div id='btn2' class='mBtn'>Or me</div><div class='mBtn'>Or even, me</div>
#2 - Does work
function byId(id){return document.getElementById(id)}
function allByClass(clss){return document.getElementsByClassName(clss)}
// useful for HtmlCollection, NodeList, String types
function forEach(array, callback, scope){for (var i=0,n=array.length; i<n; i++)callback.call(scope, array[i], i, array);} // passes back stuff we need
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
forEach(allByClass('mBtn'), addHandler);
function addHandler(elem)
{
elem.addEventListener('click', authorize, false);
}
alert('hit okay to click the 2nd button with javascript');
byId('btn2').click(); // will return from this call, since authorize relies on a valid 'this' value, and the btn gives it one.
}
function authorize(evt)
{
this.classList.add('clicked');
this.textContent = 'clicked';
}
.mBtn
{
border: solid 1px #555;
border-radius: 2px;
display: inline-block;
}
.clicked
{
color: #dddddd;
pointer-events: none;
}
<div class='mBtn'>Try me</div><div id='btn2' class='mBtn'>Or me</div><div class='mBtn'>Or even, me</div>
Use one of the following:
<body onload="script();">
or
document.onload = function ...
or
window.onload = function ...
I create a very basic jquery plugin. Simply changing the with of the div. Now, I want to use knockoutjs to dynamically update the settings of that plugin. I cant seem to get my head around how to do this or even where to start. This is what I have so far.
<div class="mychart"></div>
<input type="text" data-bind="value: chartwidth"/>
<input type="text" data-bind="value: chartheight"/>
<script src="jquery.js"></script>
<script src="knockout.js"></script>
<script src="chartjs.js"></script>
<script>
$(".mychart").nbchart({
width:'200px',
height:'200px'
});
// Here's my data model
var ViewModel = function(cwidth,cheight) {
this.chartwidth = ko.observable(cwidth);
this.chartheight= ko.observable(cheight);
};
ko.applyBindings(new ViewModel("100px","100px"));
The easiest thing you could do is subscribe to the variables:
this.chartwidth.subscribe(function (newValue) {
$(".mychart").nbchart({width:newValue});
});
However, you are violating the Cardinal Rule of Knockout, which is "Don't mess with the DOM outside of a binding handler."
A custom binding handler for your plugin would look something like this:
ko.bindingHandlers.nbchart = {
init: function (element, valueAccessor) {
$(element).nbchart();
},
update: function (element, valueAccessor) {
var config = ko.unwrapObservable(valueAccessor());
$(element).nbchart({
width: config.width(),
height: config.height()
});
}
};
and you would bind something like
<div data-bind="nbchart:config"></div>
where your viewmodel has a config variable like
var ViewModel = function(cwidth,cheight) {
this.chartwidth = ko.observable(cwidth);
this.chartheight= ko.observable(cheight);
config: {
width: this.chartwidth,
height: this.chartheight
}
};
Finally, if you are not planning to use the plugin without Knockout, you don't need a jQuery plugin. You can just write all the code as part of your custom binding handler.
I am totally new to knock-out custom binding, I am trying to integrate ckeditor with knock-out biding, I have the following binding got from Google search,
ko.bindingHandlers.wysiwyg = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var value = valueAccessor();
var valueUnwrapped = ko.unwrap(value);
var allBindings = allBindingsAccessor();
var $element = $(element);
$element.attr('contenteditable', true);
if (ko.isObservable(value)) {
var isSubscriberChange = false;
var isEditorChange = true;
$element.html(value());
var isEditorChange = false;
$element.on('input, change, keyup, mouseup', function () {
if (!isSubscriberChange) {
isEditorChange = true;
value($element.html());
isEditorChange = false;
}
});
value.subscribe(function (newValue) {
if (!isEditorChange) {
isSubscriberChange = true;
$element.html(newValue);
isSubscriberChange = false;
}
});
}
}
}
I have the following code to bind,
$(function () {
$.getJSON("/getdata", function (data) {
ko.applyBindings({
testList: [{
test: ko.observable()
},
{
test: ko.observable()
}]
}, document.getElementById('htmled'));
});
});
HTML as follows
<div id="htmled" data-bind="foreach:testList">
Data
<div class="editor" data-bind="wysiwyg: test">Edit this data</div>
</div>
The binding works and show the toolbar when I call the ko.applyBindings outside the $.getJSON method. But when I call applyBindings inside, the toolbars not appearing. Can any body help me on this? I must be missing something for sure, any help on this is greatly appreciated.
Jsfiddle Added
Working :http://jsfiddle.net/jogejyothish/h4Lt3/1/
Not Working : http://jsfiddle.net/jogejyothish/Se8yR/2/
Jyothish
What's happening is this:
Your page loads with the single div. KO has yet to be applied to this div.
document.ready() fires. The CKEditor script applied CKEditor to any matching divs (none).
You make your ajax call.
The Ajax call completes. You apply bindings.
KO inserts two new divs, neither of which has CKEditor.
In order to fix it, you need to add some code inside your ajax success function to manually initialise the CKEditors, like:
$(".editor").each(function(idx, el) {
CKEDITOR.inline(el)
});
Here it is, working in your fiddle:
http://jsfiddle.net/Se8yR/5/
The reason your working version works is because the bindings are applied in document.ready, so KO renders the two div elements in time, and the CKEditor is successfully applied to them.
CKEditor takes some time to load.
In your first example, it loads after ko applies, which works fine.
In the second example, it loads before ko applies. The problem is that CKEditor looks for the contenteditable attribute which you set with ko, so the editor is not created.
You can create it manually with:
CKEDITOR.inline(element).setData(valueUnwrapped || $element.html());
Doc
Demo
Is there a way to remove all event listens instantiated by a backbone view? For example, suppose I have the following HTML/JavaScript. When #box is clicked, I want a pop-up to say hello.
<div id="box" style="height: 100px; width: 100px; background-color: red"></div>
var Listener = Backbone.View.extend({
el: "#box",
events: {
'click #box' : 'hello'
},
hello: function () {
alert('hello!');
}
})
var listener = new Listener();
Now, I want to remove the event listener. Setting listener to something else doesn't work:
listener = ''; // doesn't work
How do I remove the event listener?
Anywhere in your View:
this.undelegateEvents();
You can then manually rebind events at a later time with delegateEvents();
http://backbonejs.org/#View-delegateEvents
http://backbonejs.org/#View-undelegateEvents
I use a method added to the Backbone.View prototype to easily clean up views:
Backbone.View.prototype.close = function() {
this.undelegateEvents();
this.remove();
}
// internal usage
this.close();
// external usage
myView.close();
EDIT 19/07/2013
Backbone v0.9.9 added the .listenTo() method to views, making it easy to unbind external events when the view is removed.
You can read more here:
Backbone.js - listenTo() documentation
StackOverflow - Backbone 0.9.9: Difference between ListenTo and on