how to set visible = false by knockout - javascript

I have posted more detailed question this is much clear and straightforward
here
hello, I am trying to set the value of list element to false by using knockout
this is my HTML
<li>
<a onclick="log(this)" data-bind="visible: true, text: $data"></a>
</li>
is there a way to say something like this :
myViewModel.items()[i].setVisible(false);

Don't set the visible binding to true set it to the variable you define in your viewModel. Also you can access individual elements of an observable array through the foreach binding. Lastly, if you want to use $data you can access the property of the individual array object directly using the "." operator. The documentation I referenced at the end of my post has more information. See below:
<div data-bind="foreach: shouldShowMessageArray">
<div data-bind="visible: $data.shouldShowMessage">
Message goes here.
</div>
</div>
<script type="text/javascript">
var myViewModel;
$(document).ready(function(){
myViewModel = new viewModel();
function viewModel() {
this.shouldShowMessage = ko.observable(false) // Message initially visible
this.shouldShowMessageArray = ko.observableArray([
{shouldShowMessage: ko.observable(true)},
{shouldShowMessage: ko.observable(false)}
]);
}
ko.applyBindings(myViewModel);
});
</script>
Knockout foreach / $data documentation

If you are looking to load the page with a starting value of visible:false, you may run into some issues with the "visible" binding.
I have had trouble with the "visible" binding when I want an element to be hidden on page load, and then made visible after some action taken by the user. You will see a flash of the hidden element while your knockout.js logic loads if you are using the visible binding. If you try to use inline CSS to set display:none on the element, then it will never become visible even when the KO logic results in a visible:true value. This is because KO applies the CSS rules after it has handled changing the element.style.display value.
One solution to this issue that I have found is to set up a CSS class that well set display to none, and then use a data binding to conditionally apply that CSS rule based on an observable.
CSS:
.hideMe { display: none; }
HTML:
<div class="hideContent" data-bind="css: { hideContent: !yourObservable() }">
<p>Content</p>
</div>

Related

showing/hiding html elements with javascript

which option among the following is better or used as a standard way to show/hide the html elements
changing element.style.display
adding/removing a separate class called hide {display: none}
any other standard way
PS: this JavaScript hide/show element question uses the first option mentioned( changes the style to block to show which may not be desired). I would like to know whether this method is used in most websites or the adding /removing a separate class or any other way
A third way in the answers below https://stackoverflow.com/a/68983509/14478972
I prefer to toggle a class using DOMTokenList.toggle():
The toggle() method of the DOMTokenList interface removes a given token from the list and returns false. If token doesn't exist it's added and the function returns true.
Well except the first and second, there is the other way.
Which is rendering the element its self.
It has a better security. as the user wont know if there is a hidden element inside the toggle div. Eg when people try to look at the html
Have a look below
I used jQuery as its easier to write. If you are not able to rewrite a JavaScript version will be happy to rewrite for you.
var items = $(".toggle");
var item = {};
// setup the auto toggle
$(".toggle").each(function(el) {
var id = new Date().getUTCMilliseconds() + $(this).index()
item[id] = $(this).find("content")
if (!$(this).hasClass("show")){
$(this).find("content").remove();
}
$(this).attr("id", id)
});
$(".toggle").click(function() {
if ($(this).find("content").length > 0)
$(this).find("content").remove();
else $(this).append(item[$(this).attr("id")])
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="toggle">
<h1>click here to toggle content </h1>
<content>
this is a test
</content>
</div>
<div class="toggle show">
<h1>click here to toggle content(start state is visible) </h1>
<content>
this is a test
</content>
</div>
Option 1 would be standard for only hiding the element, but if you would like to add other styles like transitions and pointer events option 2 is preferred

How to partially (re)apply bindings to descendants with knockout?

I created a custom knockout binding that wraps a given div in an expander. My custom binding moves the given content div to the contant-container div of the expander. After moving the content, the knockout bindings of the content child nodes would not work any more (e.g. click binding for a button inside the content div). Therefore I have to reapply the knockout bindings.
This works in most cases. However, If the content div contains for example a knockout foreach binding, reapplying the bindings means that some content is duplicated.
Example usage of the expander binding:
<div
data-bind="expander: { title: 'dataCollectionForms'}">
<div>
<div class="expander-content">
<button
data-bind="click: $root.addAction, text: 'Hinzufügen'"></button>
<div
data-bind="foreach: listOfButtons">
<button
data-bind="click: $root.buttonClickAction">
</button>
</div>
</div>
</div>
</div>
My code for moving the content div:
function moveExpanderContentToContentContainer($contentContainer, expanderContent) {
try {
//Move the expander content to the content container
//The content will not be cloned but moved. For more info see:
//https://api.jquery.com/append/
var $expanderContent = $(expanderContent);
$contentContainer.append($expanderContent);
$contentContainer.addClass('expander-content-container panel-body');
$expanderContent.addClass('expander-content');
ko.applyBindingsToDescendants(bindingContext, expanderContent);
} catch (appendException) {
var errorMessage = 'Could not append expander-content to expander-content-container.';
logger.logError(errorMessage, appendException, self, true);
}
}
If I remove the line
ko.applyBindingsToDescendants(bindingContext, expanderContent);
the click actions of my three buttons do not work any more:
If I keep the line, the click actions work but the buttons are duplicated:
=> How can I update the bindings of the moved content in a way that fixes
the click bindings and does not duplicate my buttons?
=> If this moving work flow does not work at all, what is a better way to create a custom knockout binding that wraps a given content in a collapsable expander?
I could find some related articles but no solution to my specific issue:
http://knockoutjs.com/documentation/custom-bindings-controlling-descendant-bindings.html
How to clear/remove observable bindings in Knockout.js?
ko.applyBindingsToNode vs. ko.applyBindingsToDescendants
Remove knockout js bindings on cloned element
https://github.com/knockout/knockout/issues/1821
I solved the issue by not moving the content div at all but building the expander around it.
My original strategy was to have a reusable expander view + view model and to move the content div from the original location to the newly composed expander view. Moving around the already bound content was no good idea, I guess.
The new strategy adapts the already existing divs and composes only the header for the expander.
Nevertheless thank you for your thoughts.
I use following code for recreating content of the passed DOM element (having view model + template selector):
function renderIntoElement(element, viewModel, templateSelector) {
templateSelector = templateName || "#myTemplateId";
var $element = $(element);
var templateHtml = $(templateSelector).text(),
$element.children().remove();
$element = $element.append(templateHtml),
ko.applyBindings(viewModel, $element.children()[0]);
}
Hope this helps.

Applying jQuery event functions to new Knockout.js array elements

I have a Knockout.js viewmodel with a list of products, which are populated by an ASP.NET Web API call:
// Define viewmodel
var myViewModel = {
products = ko.observableArray([]);
};
// Apply knockout bindings
ko.applyBindings(vm);
// Function that obtains product data
function listProducts(viewmodel) {
var productsQuery = "api/products/get";
// Send an AJAX request
$.getJSON(productsQuery).done(viewmodel.products);
}
When I call listProducts, each element is added successfully to the ff. HTML <ul>:
<ul data-bind="foreach: products">
<li class="item">
<data-bind="text: productName">
</li>
</ul>
However, when each item is added, the jQuery function that applies to my .item elements:
$(".item").click(function () {
$(this).toggleClass("selected");
});
does not get applied to these newly added elements.
Question: How do I add elements to the Knockout.js observableArray that will also inherit their corresponding jQuery methods?
Basically you need to go back to the knockout docs and read, read, read! Forget doing this with jquery, it's just not the ko way. Knockout frees you from this kind of coding style, you just need to grok it.
hint:
use the click binding and the css binding
http://knockoutjs.com/documentation/css-binding.html
As an aside you can also do this:
$.getJSON(productsQuery).done(viewmodel.products);

Knockout binding not working incase of inline editing

I was trying to create an inline editing with knockout.
I created both 'span' and 'input' for same field.
On click of span I hide the span and 'show' the 'input'.
But the change in the input is not reflection on the span.
My Html field
<td>
<span data-bind="text: name" style="display: inline;">Furious Lizard</span>
<input data-bind="value: name" style="display: none;" type="text">
</td>
My code for inline
$('td').on('click', function () {
var spanElement = $(this).find('span');
$(this).find('span').hide();
$(this).find('input').show().select().on('blur', function () {
$(this).hide();
spanElement.show();
});
});
Why isn't the binding working?
JSFiddle
I believe the reason is that eventhough you are binding to an observableArray, the properties on your objects are not themselves observable, so when the property is altered other bound elements aren't notified of the change.
I have edited your sample:
http://jsfiddle.net/879Pk/3/
There you can see that the first element in your data, instead of just being standard properties, they are observable as well:
{
name: ko.observable("Well-Travelled Kitten"),
model: ko.observable(352),
price: 75.95
}
NOTE: I didn't modify the price since you use it below for calculations. For that to work you'd have to modify all prices to be observable, and then while computing actually call the observable (using parenthesis) in order to get the actual value.
In order to avoid having to manually create the observables for each property, Knockout has a plugin called "Mapping" (http://knockoutjs.com/documentation/plugins-mapping.html) which does exactly that, using the following syntax:
var viewModel = ko.mapping.fromJS(data);
Now, regarding your second JSFiddle, I have just made a few corrections:
http://jsfiddle.net/879Pk/5/
When you were adding the element the properties on the new one weren't observable, and you were also missing the parenthesis when evaluating the price property.
you want that the data writen in the input to be visible in the span element as text?
$(this).find('span').html($(this).find('input').val());

Set a parents parent css using javascript/ knockout

I've got some checkboxes within a table and I want to the css of their parent to be dependent upon whether it's checkbox is checked or not. I can't seem to get this to work and was hoping you could point me in the right direction.
At the moment, I've got a setCss() function on the checkbox 'onclick' method but am getting the resource undefined error.
I've added jsFiddle
function setCss() {
if (this.checked)
$(this).closest('td').className = "selected";
else
$(this).closest('td').className = "deselected";
}
You can do this quite simply using the knockout css binding:
<td data-bind="css: {'selected': selected,'deselected': !selected() }">
<!-- existing content -->
</td>
I've updated your fiddle to work in this way.
This binding means "set the 'selected' class if selected() evaluates to a truthy value, and set the 'deselected' class if it evaluates to falsey".
You could also neaten up your CSS by using a :not(selected) instead of an explicit deselected class

Categories