What you're doing should work provided you're executing that code when the element exists (example).
In your example, (Turns out that was an error in the code in the question, you meant to be targeting the #sec
is the element with the with
binding. with
will omit descendant elements of #sec
if the value of its with
binding (selectedView
in your example) is null
or undefined.
So #sec
will always be there, just not the span within it. (Example)span
.)
What's the best-practice for dynamically styling my elements?
Best practice would be to use CSS, not JavaScript code, to style elements. Possibly in combination with the css
binding, but not necessarily.
Another option is to do a custom binding which does the styling as part of the KO stuff. Custom bindings are very common in KO stuff. Since KO knows it's not rendering the element, it doesn't run the custom binding against it, and there's no error.
Or of course, if you do have elements that may or may not be present because you've used with
or if
, test they exist before using them:
var x = document.getElementById("span");
if (x) {
// Do stuff here
}
But again, recommendations in order:
Use CSS, not JavaScript, to style elements (possibly in conjunction with the
css
binding to apply a class to it); orUse a custom binding if there has to be per-element code run (the great thing here is you define them once and reuse them); or
Use a guard (
if (x) { ... }
)
Here's an example of a custom binding that makes the element's color red if the value of the binding is more than 12 characters long, blue otherwise:
ko.bindingHandlers.colorByLength = {
update: function(element, valueAccessor/*, allBindings, viewModel, bindingContext*/) {
var val = ko.unwrap(valueAccessor());
element.style.color = (val && val.length > 12) ? "red" : "blue";
}
};
Complete Example: Live Copy
<!DOCTYPE html>
<html>
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<meta charset=utf-8 />
<title>Example Custom Binding</title>
</head>
<body>
<section data-bind="with: selectedView" id="sec">
<span data-bind="text: title, colorByLength: title" id="span"></span>
</section>
<section data-bind="with: anotherView" id="sec">
<span data-bind="text: title, colorByLength: title" id="span"></span>
</section>
<section data-bind="with: nullView" id="sec">
<span data-bind="text: title, colorByLength: title" id="span"></span>
</section>
<script>
(function() {
"use strict";
// Custom binding
ko.bindingHandlers.colorByLength = {
update: function(element, valueAccessor/*, allBindings, viewModel, bindingContext*/) {
var val = ko.unwrap(valueAccessor());
element.style.color = (val && val.length > 12) ? "red" : "blue";
}
};
var PseudoViewModel = {
// This one will be red
selectedView: {
title: "This is the title"
},
// This one will be blue
anotherView: {
title: "Short title"
},
// And of course, this one isn't rendered at all
nullView: null
};
ko.applyBindings(PseudoViewModel);
})();
</script>
</body>
</html>