Knockout css bindings within a foreach - css

I'm trying to do some templating for the site I'm working on the make it more reusable. To do this I'm using knockout to help with data-binding to transfer info from a json fine.
However, I'm having quite a bit of trouble passing a css property object to a span element within my template.
My html template kind of looks like this
<div data-bind="cssProperties: properties, css: { hidden : EvalDisplay() == false }">
<p>
<!-- ko foreach: options -->
<label class="btn">
<input type="checkbox" />
**<span class='optionText' data-bind="cssProperties: $parent.properties, html: Value"></span>**
</label>
<!-- /ko -->
</p>
</div>
The span with the asterisks next to it is what's giving me trouble. If I move that outside of the foreach loop then it works fine and the property is added, but if I keep it inside that loop where I need it to be it's just not being applies.
Any help would be great. I am very new at knockout so I don't know all the cool little tricks yet.
And before you ask, yes the css property has to be in the json and not in a css sheet. It needs to be where non-technical people can access it to change it.

Related

How to reflect BEM blocks in Aurelia views

I'm about to start a new project using Aurelia and I'm considering to use it in conjunction with CSS BEM methodology.
First question: Is this basically considered a good match or are there any alternatives which "fit" better with Aurelia?
Main question:
Best explained with an example for some custom Aurelia view (an app header):
<template>
<div class="AppHeader">
<span class="AppHeader-logo"></span>
<span class="AppHeader-text"></span>
<app-menu></app-menu>
</div>
</template>
When embedded into another view, this leads to a resulting DOM like this (simplified):
<app-header>
<div class="AppHeader">
<span class="AppHeader-logo"></span>
<span class="AppHeader-text"></span>
<app-menu>
<!-- ... -->
</app-menu>
</div>
</app-header>
Obviously, the wrapper div with the AppHeader class is kind of superfluous since there's also the app-header tag. Unfortunately it doesn't seem to be possible to assign the CSS class AppHeader (which is needed for BEM) to the base element of the view (the template tag in the view file).
Are there any alternative ways that I'm not aware of or is it considered "good" practice (or at least acceptable) to have many wrapper elements inside views which somehow bloat the DOM?
I just realized, that putting custom classes on the custom elements themselves (the template) actually works, so I can simply write something like this:
<template class="AppHeader">
<span class="AppHeader-logo"></span>
<span class="AppHeader-text"></span>
<app-menu></app-menu>
</template>
Edit / Additional info
This won't work if the view is a "base view" of a route since the template element won't be rendered at all in this scenario but is replaced by the router-view element.
I believe that even a hundred extra DOM nodes is not a problem for contemporary browsers but if it's really important to avoid them you may try custom tags instead of classes (see list of restrictions here https://en.bem.info/methodology/faq/#why-are-custom-tags-not-used-for-blocks-in-bem).
Perhaps the #containerless will solve your problems:
In your view model:
#containerless
export class AppHeader {
...
}
In this way, the <app-header> container will not be rendered.
If your component is a view-only component, you can declare containerless in the <template> tag:
<template containerless>
<div class="AppHeader">
<span class="AppHeader-logo"></span>
<span class="AppHeader-text"></span>
<app-menu></app-menu>
</div>
</template>

Styling bootstrap buttons in mvc is killing

I'm using VS and mvc. I have a Html.BeginForm which takes a randomKey as a string in the input box. There is a retrieve button that currently abuts the input box and I just want to add a margin to the button. In the site.css there is a .retrieveButton class but it doesn't seem to override the bootstrap css. Help please!
<div>
#Html.EditorFor(model => model.RandomKey...placeholder = "Enter your 8 digit key" } })
<div class="form-group">
<div>
<input type="submit" value="Retrieve" class="btn btn-default retrieveButton"/>
</div>
</div>
</div>
In case of duplicate class names, the last CSS file wins (it augments or redefines what came before it).
So make sure that your CSS files are added to the page in the correct order. Probably your personal CSS should come after Bootstrap CSS. To do this for MVC 4+, see file App_Start -> BundleConfig.cs.
For more in-depth info about bundling in MVC see e.g. this: http://timgthomas.com/2012/09/a-quick-start-of-asp-net-mvc-4s-bundling/
You can try using !important in the CSS or you can try using a more direct selector.
When you have multiple statements that try to apply the same property to the same element then the statement with the more precise selector will be used.
try:
.form-group > .btn.btn-default.retrieveButton {
}
You can read more about this here:
https://www.smashingmagazine.com/2007/07/css-specificity-things-you-should-know/

Get rid of unneeded DIVs in my if binding knockout

I have an observable array with the following structure (where type can be only text or img):
ko.observableArray([{
type: 'text',
info: 'Hello'
},{
type: 'img',
info: 'http://cdn.zendesk.com/images/documentation/apps/logo-small.png'
}]);
Depending on the type I want to output either image or a bunch of text. So I am using the if binding. The result looks the way I expected, but the problem is in the underlying html:
<div data-bind="foreach: elements">
<div data-bind="if: type == 'text'"><div data-bind="text: info">Hello</div> </div>
<div data-bind="if: type == 'img'"></div> // Do not want it to be here
<div data-bind="if: type == 'text'"></div> // Do not want it to be here
<div data-bind="if: type == 'img'"><img data-bind="attr: { 'src': info}" src="http://cdn.zendesk.com/images/documentation/apps/logo-small.png">
</div>
</div>
It keeps inserting empty <divs> if the if statement returns false.
When I tried to achieve what I wanted with putting if and text binding in the same element I got the following error:
Multiple bindings (if and text) are trying to control descendant
bindings of the same
How can I get rid of unneeded DIVs in my output html with the if binding?
If this is impossible to achieve with if-binding, is there a way to do this somehow else? Because if I will have not only type = 'text' or 'img' but also 'video' and a dozen of other things I will have all them empty sitting there just as an artifact.
If you don't need the extra divs you can use the containerless control flow syntax of the if binding, which is based on comment tags:
<div data-bind="foreach: elements">
<!-- ko if: type == 'text' -->
<div data-bind="text: info"></div>
<!-- /ko -->
<!-- ko if: type == 'img' -->
<img data-bind="attr: { 'src': info}" />
<!-- /ko -->
</div>
Demo JSFiddle.
And the generated DOM will look like:
no extra divs only a few extra comments.
To get rid of these comments you can use templates.
You cannot get rid of the extra divs. I use the if binding do what you're doing on a regular basis.
The error you're getting simply indicates that you have competing bindings, which is expected with if and visible bindings. Your if and visible bindings should always be one div higher, so to speak.
Below is a screenshot of my DOM using Google's dev tools. The web application is actually running, and I use the if binding to reveal the view the user has chosen.
The extra divs are simply an artifact of the if binding.
If you think about it, if the if binding were to disappear altogether, what would be left in the DOM to reconstitute it when the condition is satisfied and that portion of the view should be shown?
UPDATE
Upon reconsidering the template approach, you could push the logic into the viewmodel (vm), bind the name of the template to an observable on the vm, and then dynamically set the template based on that logic. But, the templates themselves are going to hang around in the DOM. So I don't think there's a net gain here.

metamorph tags interfering with table cell layout

I'm building a table cell using two bound ember.js views on data. When I do that, ember.js inserts its metamorph tags such that it can update the view later.
<td>
<a data-ember-action="14">
<div id="ember2065" class="ember-view">
<script id="metamorph-102-start" type="text/x-placeholder"></script>
02/04/2012
<script id="metamorph-102-end" type="text/x-placeholder"></script>
</div>
#
<div id="ember2072" class="ember-view">
<script id="metamorph-103-start" type="text/x-placeholder"></script>
$61.81
<script id="metamorph-103-end" type="text/x-placeholder"></script>
</div>
</a>
</td>
These tags cause the date and the price below to line wrap within the cell. Is there a CSS styling that I can apply to these tags to make them not effect line breaking?
It strongly depend on your full case. It seems to me that using views is superfluous here, but maybe I am missing some information.
Here are some working samples: http://jsfiddle.net/MikeAski/QCbGN/
Maybe providing more context would help to have better sample.
Put this in your stylesheet to prevent line breaks from ember views:
div .ember-view {
display: inline;
}

How do I bind a dynamic set of jQuery Mobile buttons using Knockout.js?

I'm using jQuery Mobile (jQM) and Knockout.js (ko) to develop an application. In this application, I need to generate a variable number of buttons that are defined by a constantly updating web service.
So, in my markup, I have:
<div id="answerPage-buttons" data-bind="foreach: buttonsLabels">
<button data-role="button" data-inline="true" data-theme="b" data-bind="text: text, click: $root.submitAnswer" />
</div>
buttonLabels is a list of short strings returned from the web service. It's defined as:
self.buttonLabels = ko.observableArray();
This all works fine when the buttons are not "jQM styled". However, when I style them using:
$("#answerPage-buttons").trigger("create");
problems arise during the update.
The issue seems to be that jQM wraps the buttons in a div (with a sibling span) to make them all nice and mobile looking. However, when the ko applies the updates via the bindings, it only removes the tags, leaving the surrounding stuff, and adds new button tags - which are then also styled by the jQM trigger call.
So, I end up with an ever-growing list of buttons - with only the last set being operational (as the previous ones are gutted by the removal of their button element, but all the styling remains).
I've managed to address this, I think, by placing the following call immediately after the observable is updated:
$("#answerPage-buttons div.ui-btn").remove();
However, my feeling is that there's probably a better approach. Is there?
I found a solution.
If I surround the buttons with a div, it seems to work - e.g.
<div id="answerPage-buttons" data-bind="foreach: buttonsLabels">
<div>
<button data-role="button" data-inline="true" data-theme="b" data-bind="text: text, click: $root.submitAnswer" />
</div>
</div>
I'm guessing this is because the markup added by jQM remains "inside" the markup replicated by ko. Without the div, jQM wraps the button tag, which was the immediate child of the tag that contains the ko foreach binding.

Resources