Knockout if, click and visible binding - data-binding

Very simple question.
Say I have this HTML in my view():
<a id="btnXYZ" class="" data-bind="click: editAction">Button</a>
Simple anchor tag that would execute editAction if clicked.
Now if I have something like this:
<a id="btnXYZ" class="" data-bind="click: editAction, if: isOwner(ref)">Button</a>
Let say isOwner(ref) evaluates to true, I see anchor with no text. Not good.
Expected result would be same as before (first example).
And now lets say I have something like this:
<div class="">
<a id="btnX" class="" data-bind="click: editAction, if: isOwner(ref)">Button</a>
<a id="btnY" class="" data-bind="click: editAction, if: isOwner(ref)">Button</a>
<a id="btnZ" class="" data-bind="click: editAction, if: isOwner(ref)">Button</a>
</div>
Same as before, if isOwner(ref) evaluates to true see empty anchor tags.
Question:
How can I bind if: isOwner() to manage button visibility?
i.e.
if isOwner(ref) evaluate to true I should see a proper link/button
if isOwner(ref) evaluates to false I should see no link/button at all

You can use virtual elements to achieve that:
<!-- ko if: isOwner(ref) -->
<a id="btnXYZ" class="" data-bind="click: editAction">Button</a>
<!-- /ko -->
Also if you want you can display something completely different instead like:
<!-- ko ifnot: isOwner(ref) -->
whatever you want
<!-- /ko -->

You want to use the visible binding. This will show and hide the entire element, while the if binding just controls the contents of the element.
Here's a demo.
However in this case, I would go with #Vladimirs answer as you can wrap the virtual element around all 3 of your buttons, rather than binding them all individually.

Related

Add class to ian:accounts-ui-bootstrap-3 SELECT tag when rendered [Meteor JS + Blaze]

Meteor 1.6.1.1 is the latest version of my project. I am using package ian:accounts-ui-bootstrap-3 instead of accounts-ui. I have added a custom field as <select> in the code.
What I get on Screen is as below.
When I saw the HTML code, it is not adding class="form-control" to select tag.
below is the code when I inspect element on UI using Chrome.
<li id="login-dropdown-list" class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Sign in / Join <b class="caret"></b></a>
<div class="dropdown-menu">
<div class="select-dropdown">
<label>State</label><br>
<select id="login-state">
</select>
</div>
<button class="btn btn-primary col-xs-12 col-sm-12" id="login-buttons-password" type="button">
Create
</button>
<button id="back-to-login-link" class="btn btn-default col-xs-12 col-sm-12">Cancel</button>
</div>
</li>
All I want is to add class="form-control" to the select tag dynamically when component loads on screen and it must look like below;
I have tried below code, but it is not working;
Template.HomePage.onRendered(function () {
document.getElementById('login-state').classList.add('form-control');
});
Well, I tried one way to achieve this is by using Template event as below,
Template.HomePage.events({
'click #login-dropdown-list': function(event){
//document.getElementById('login-state').classList.add('form-control');
$('#login-state').addClass('form-control');
}
});
As you can see, the component gets loaded inside the li tag with id="login-dropdown-list". I simply loaded the class on click event. Even the commented code works fine.
Is this a good solution? please let me know if there much better answer to this? If it works I will definitely accept and upvote the answer.

Wrong data context in modal

I can't figure out why this Bootstrap modal receives the wrong data context.
Let's begin with my templates (excluding the modal for now). The first iterates through a list of items fetched by itemsList:
<template name="CategoryItems">
<ul>
{{#each itemsList}}
{{> Item}}
{{/each}}
</ul>
</template>
itemsList looks like this, by the way:
itemsList: function() {
return Items.find()
}
The inside template, Item, details just how these items should appear:
<template name="Item">
<li>
<span class="item-name">{{name}} </span>
<a href="#" class="anchor-item-edit" data-toggle="modal" data-target="#edit-item-modal">
<span class="fa fa-2x fa-pencil-square-o"></span> //Font Awesome icon
</a>
{{> EditItemModal}}
</li>
</template>
So basically it displays the name of the item fetched from the database and then provides an edit button that opens the edit-item-modal. The modal itself is placed here (it's hidden by default) so that it gets the correct data context, however that doesn't seem to work.
When the edit link is clicked, the modal opens. Excluding a lot of markup, it looks like this:
<template name="EditItemModal">
<div class="modal fade" id="edit-item-modal" tabindex="-1" role="dialog" aria-hidden="true">
<h4>{{name}}</h4>
</div>
</template>
The name, however, always displays the name of my first item in the list, ignoring what I actually clicked on.
A very strange thing, though, is that if I include a helper check inside the modal like so,
<template name="EditItemModal">
{{checkDataContext}}
//the other stuff
</template>
and makes the helper look like this,
Template.EditItemModal.helpers({
checkDataContext: function() {
console.dir(this)
}
})
then all the correct items are spit out in the console as soon as I load the page.
What's going on here?
Your modal markup only defines one shared ID between all of your modals, which is not valid HTML and ends up being the root of your problem.
When you click on any button triggering the modal, it's going to show up the first modal it finds in your markup, which always happens to be the first one.
You need to decorate your modals IDs with your items IDs (since they come from a Mongo.Collection), your markup will no longer contain duplicated modal IDs and your code will run as expected.
<template name="EditItemModal">
<div class="modal fade" id="edit-item-modal-{{_id}}" tabindex="-1" role="dialog" aria-hidden="true">
<h4>{{name}}</h4>
</div>
</template>
<template name="Item">
<li>
<span class="item-name">{{name}} </span>
<a href="#" class="anchor-item-edit" data-toggle="modal" data-target="#edit-item-modal-{{_id}}">
<span class="fa fa-2x fa-pencil-square-o"></span> //Font Awesome icon
</a>
{{> EditItemModal}}
</li>
</template>

actionlink manipulates html render order in nested anchor

I'm having a problem and i'm really puzzled by it.
My markup is simple enough:
#foreach (var item in Model.Items)
{
<a class="mapIconUnit" id="pinDelete-#item.PinGuid.ToString()">
#Url.Action("DeletePin") <!-- testing purposes -->
#(Ajax.ActionLink("x", "DeletePin", MapAdministrationController.Routes.DeletePin(item.PinGuid), new AjaxOptions()
{
OnSuccess = "onMapPinDeleted",
Confirm = Resources.Resource.msg_GenericDeleteConfirmationQuestion
}
))
</a>
}
Now what i would expect to render from this is:
<a class="mapIconUnit" id="...">
... rendered url
<a href="..." etc>x</a>
</a>
But what i am getting is:
<a class="mapIconUnit" id="...">
... rendered url
</a>
<a href="..." etc>x</a>
What am i doing wrong here? The markup is too simple for it to be wrong to cause such a thing?
It's illegal to nest an anchor element inside another anchor element, more info can be found in the W3C specs: http://www.w3.org/TR/html401/struct/links.html#h-12.2.2
Links and anchors defined by the A element must not be nested; an A element must not contain any other A elements.
So either razor or the webbrowser renders the elements correctly (i.e. place them next to each other).

Single page, carousel-style, slide website:Navigate to previous slide, on browser back button, without defaulting to home slide?

I am making a website that uses div/slides to hold content. They are positioned inside a container with overflow:hidden. A navigation bar uses document.getElementById('box').style.left='0px' to alter the div positions to bring required div into view. The left CSS property is changed 'onclick' to bring the targeted div into view and push the others out of container viewing area. Transitions animations are handled by CSS.
Here a link to the fiddle example. http://jsfiddle.net/HyHmF/1/ . HTML Code is as follows,
<a class="boxes" href="#" onclick="document.getElementById('box1').style.left='0px';
document.getElementById('box2').style.left='200px';
document.getElementById('box3').style.left='400px';">Box 1</a>
<a class="boxes" href="#" onclick="document.getElementById('box1').style.left='-200px';
document.getElementById('box2').style.left='0px';
document.getElementById('box3').style.left='200px'";>Box 2</a>
<a class="boxes" href="#" onclick="document.getElementById('box1').style.left='-400px';
document.getElementById('box2').style.left='-200px';
document.getElementById('box3').style.left='0px'">Box 3</a>
<div id="boxcontainer">
<div id="box1">Box 1</div>
<div id="box2">Box 2</div>
<div id="box3">Box 3</div>
</div>
My issue is this. How can I make the browser back button to change the CSS to bring the previous displayed div into view. That is, without reverting back to the 'home' div.
I am reasonably familiar with javascript and jquery. I know the answer lies in JQuery BBQ pushstates and hashtags. Unfortunately I haven't been able to implement these into my site # http://www.sumoto.com.au. The fiddle is basically this site, scaled down, for ease of explaining my dilemma.
Essentially, how can I save a 'snapshot', of the current css view to a hashtag url, and call this 'save' through the browser back/forward navigation?
I solved my problem!
I removed all the cluttered onclick lines from the a elements. And added id's for each one. The actual hashtag/browser back button functionality is provided by hashchange by Ben Alman, and of course, JQuery.
The revised HTML is:
<a class="boxes" id="link1" href="#box_1">Box 1</a>
<a class="boxes" href="#box_2">Box 2</a>
<a class="boxes" href="#box_3">Box 3</a>
<div id="boxcontainer">
<div id="box1">Box 1</div>
<div id="box2">Box 2</div>
<div id="box3">Box 3</div>
</div>
The Javascript
$(document).ready(function() {
$(window).hashchange( function(){
var hash = location.hash;
var lc1 = $("#link1")
if (lc1.attr('href') === hash) {document.getElementById('box1').style.left='200px';}
if (lc1.attr('href') !== hash) {document.getElementById('box1').style.left='0px';}
});
$(window).hashchange();
});
The a links are targeted by the script and assigned a var; "lc1". An if statement checks if the hash of lc1 (the link) is equal to the browser url. If it is then the css manipulation is performed and the sliding movement occurs. If it isn't (for example when the user clicks back) the boxes return to their original (or previous) conformation.

Bind boolean to class

I have a list of items and I want to highlight the "selected" one (this is linked to another interface, so using pure CSS will not work). I'm guessing I could do this:
<!-- ko if: isSelected -->
<span class="selected">
<!-- ko endif -->
<span class="myItem">content goes here</span>
<!-- ko if: isSelected -->
</span>
<!-- ko endif -->
and maybe even this:
<span class="myItem<!-- ko if: isSelected --> selected<!-- ko endif -->">
content goes here
</span>
But I suspect there is a better way. I have been unable to find it.
According to the documentation here: http://knockoutjs.com/documentation/css-binding.html
<span class="myItem" data-bind="html: name, css: { selected: isSelected()"><span>
Works great!

Resources