Is it possible to not omit some opts on the outermost element in a custom Riot tag? - riot.js

I'm using RiotJS v3.9
I've written a custom tag that accepts a few opts. The problem is that the markup it generates includes all of those opts on the outermost element, in addition to the interior tags where I explicitly deposit them. I do not want any opts to appear on the top element unless I make that happen.
In this case, my custom tag display a list of items. One of the opts it accepts is the value for a specific data- attribute on each list item. So, I want data-something={opts.itemSomething} to appear on each list item, but I do not want that to appear on the wrapper.
// my-list.tag
<my-list>
<ul data-something={ opts.something }>
<li
each={ item in opts.items }
data-something={ parent.opts.itemSomething }
>
{ item }
</li>
</ul>
</my-list>
Using it:
<my-app>
<my-list
something="parent-value"
item-something="child-value"
items={['one', 'two', 'three']}
/>
</my-app>
What it emits into the page:
<my-list something="parent-value" item-something="child-value">
<ul data-something="parent-value">
<li data-something="child-value"> one </li>
<li data-something="child-value"> two </li>
<li data-something="child-value"> three </li>
</ul>
</my-list>
I don't want the emitted <my-list> tag to have either the parent-value or the child-value on it. I only want those attributes to appear on the <ul> and <li>, like I coded it.
// bad output
<my-list something="parent-value" item-something="child-value">
// good output
<my-list>
Is this possible?
Also, I know from working with React that I'm likely to encounter future cases where I want some of the opts to appear on the wrapper while hiding others. So, ideally I'd like to know how to control this behavior on a per-opt basis.

you can remove the unwanted attributes in both the "updated" and "mount" event.
check this demo
However I strongly suggest you to switch to riot#5!!

Related

Using dynamic IDs in a string in a VueJS

I'm using a UIKit library for a tab component that listens to a uk-tab property that targets an id. The problem with this, is that it creates the same ID for every tabbed component. I like the UI, but whoever thought of this, didn't think too far into it. I could fix it by making the id dynamic but I am having trouble calling it in the uk-tab property because it is rendering a string. Coming from a react background, I would do a string literal and some JSX, something like #item-${_id}to show #item-12, #item-13....and so on. But That's not working. How can I do this in Vue?
Here is an example of how it works
<div class="mytrigger">
<ul uk-tab="connect: #component-tab-left; animation: uk-animation-fade">
</div>
<div class="mytargetedtab">
<ul id="component-tab-left" class="uk-switcher">
</div>
Here is an example of how what I need
<div class="mytrigger">
<ul uk-tab="connect: #_uid+'switcher'; animation: uk-animation-fade">
</div>
<div class="mytargetedtab">
<ul :id="_uid+'switcher'" class="uk-switcher">
</div>
Check out the dev tools. It should be 810switcher, but instead is taking it as a string
Any ideas? Thanks
I believe what you need is:
<ul :uk-tab="`connect: #${_uid}switcher; animation: uk-animation-fade`">
Or if you prefer not to use backticks:
<ul :uk-tab="'connect: #' + _uid + 'switcher; animation: uk-animation-fade'">
The output will be:
<ul uk-tab="connect: #22switcher; animation: uk-animation-fade">
A few notes:
Using a : is short for v-bind: but don't let the name confuse you. v-bind doesn't necessarily bind anything, it just makes the attribute value a JavaScript expression.
I'd avoid using numbers at the start of element ids, I've seen that cause problems in the past. It'd be better to put the numbers at the end.
The underscore at the start of _uid indicates that it's private to Vue. There are no guarantees about what form it will take or whether it will even exist going forward.
Use data-uk-tab instead of uk-tab like below.
<div class="mytrigger">
<ul data-uk-tab="{connect: `#${_uid}switcher`, animation: 'uk-animation-fade'}">
</div>
<div class="mytargetedtab">
<ul :id="_uid+'switcher'" class="uk-switcher">
</div>
For more information => Switcher with tabs
You can use any javascript expression in a data binding in vue. So, if you bind a string template to the attribute, it'll populate what you expect.
<ul :uk-tab="`connect: #${uid}switcher`'; animation: uk-animation-fade">

How to conditionally display client-side data with Aurelia

Is there a way in Aurelia to say 'If x == this, then show this'?
To be specific, I have an array of data that looks something like this:
[
{objectID: 1, customDataArray: [1,2,3,4], customDataType: { cdt: "Troops" }}
]
This array obviously has multiple rows that look like the one above where it's passing me an array of custom values that I need to reference. Those values could be the IDs of different 'groups' in our system. That's why we are passing in an object the contains what type of custom data it is. e.g. "Troops"
So what's happening is on Activate, I'm fetching all this data from my API and storing it in a variable. Well based on whether the custom data type is "Troops" or something else, I want to show a different input label. For example, if it is "Troops," I want to show a label that says "input troop id's" and so on.
Also, sometimes the customDataType isn't required so it comes in as null. So in that case, I want to show something different. Not sure how to handle this one..
The if custom attribute or the show custom attribute would work. Unfortunately, we don't have a switch or else type of setup.
<label if.bind="p.customDataType.cdt === 'Troops'">Input Troop Ids</label>
<label if.bind="p.customDataType.cdt !== 'Troops'">Something Different</label>
You could try if if.bind could be useful for this, as below:
<ul>
<li repeat.for="obj of data" if.bind="obj.customDataType">
<span>${obj.customDataType.cdt}</span> -
<strong repeat.for="cda of obj.customDataArray">${cda}, </strong>
</li>
<li repeat.for="obj of data" if.bind="!obj.customDataType">
<span>No CustomDataType</span>
<strong repeat.for="cda of obj.customDataArray">${cda}, </strong>
</li>
</ul>
Here is a plunker that shows this in action: https://gist.run/?id=21991c490810a4acf2e38cec99614bbd

vue.js - Change text based on default/clicked class

Given the following:
<div id="#my-container">
<div class="title">Companies</div>
<div class="tab active tab-apple">Apple</div>
<div class="tab tab-google">Google</div>
</div>
When page is loaded without any tab clicks yet, whichever tab with the default active class, needs to go in the .title div. For the example above, <div class="title">Apple</div>
On click of a tab, the class is switched to active, and vue.js needs to update the .title div once again.
How can this be done with vue.js? I've tried but not able to get it to work as intended.
The answer by David is one way to do it. But Vuejs offers in-line computations for this. So, no need to hook into any CSS event. Here's some code to explain:
Create a data property active_tab, just like David mentioned. And then bind it's value just like he's done it. In your tabs, add an click event and at that event, assign appropriate value to active_tab.
<div class="tab active tab-apple" #click="active_tab = Apple">Apple</div>
<div class="tab tab-google" #click="active_tab = Google">Google</div>
Now, to dynamically assign the active class to the respective tab, make the class attribute, a computed property, like this:
<div
:class="['tab', active_tab == 'Apple' ? 'active' : '', 'tab-apple']"
>
Apple
</div>
What this code is basically doing is, :class makes class a computed property. Then the commas in the array divide the statement. So, the computation will always add tab and tab-apple classes. But, only if active_tab == 'Apple' then ? add 'active' else : add ''
Not sure which CSS framework you are using, but normally I hook into the events thrown by the tab switching (many CSS frameworks provide this access). Once hooked into it, you can write a Vue custom directive that will take that event and use it to update a VM attribute that indicates which tab is active.
Then you can use normal mustache templating to get it into your template:
<div class="title">{{ active_tab }}</div>

Uncaught TypeError on second onclick event using this.innerHTML

Everyone, I have a rather weird problem.
In an HMTL unordened list I have several list elements with onClick events, and they all call the same function.
<ul>
<li onClick="Javascript:show(this.innerHTML); alert(this.innerHTML);">1</li>
<li onClick="Javascript:show(this.innerHTML); alert(this.innerHTML);">2</li>
<li onClick="Javascript:show(this.innerHTML); alert(this.innerHTML);">3</li>
<li onClick="Javascript:show(this.innerHTML); alert(this.innerHTML);">4</li>
<li onClick="Javascript:show(this.innerHTML); alert(this.innerHTML);">5</li>
<li onClick="Javascript:show(this.innerHTML); alert(this.innerHTML);">6</li>
<li onClick="Javascript:show(this.innerHTML); alert(this.innerHTML);">7</li>
<li onClick="Javascript:show(this.innerHTML); alert(this.innerHTML);">8</li>
<li onClick="Javascript:show(this.innerHTML); alert(this.innerHTML);">9</li>
<li onClick="Javascript:show(this.innerHTML); alert(this.innerHTML);">0</li>
</ul>
This is the Javascript function:
function show(ID){
show = document.getElementById(ID);
notShow = document.getElementsByClassName("visible")[0];
if (typeof notShow !== "undefined"){
notShow.classList.toggle("hidden");
notShow.classList.toggle("visible");
}
show.classList.toggle("hidden");
show.classList.toggle("visible");
}
for some unknown reason, the function works fine when I click one of the <li> elements first, but the second time I do that I get an error:
Uncaught TypeError: object is not a function ACNL.php:31
I think the error is not inside the javaScript function, but in the HTML-element that calls the function.
Any help would be appreciated!
I see a few problems here. In no particular order:
It would probably be safest to change the inner variable name show to something else since your function is also called show(...).
Declare variables with the var keyword to avoid populating the top namespace.
You're retrieving DOM elements by ID, but none of your DOM elements (in the above example) have ID attributes. You'll want to add them to your li items at least, e.g. id="1"
If these elements don't have visible to start off with, you'll add both visible and hidden when you "toggle".
If you toggle visible and hidden on the li items, then notShow = document.getElementsByClassName("visible")[0]; should probably change, as you will be retrieving the li items once they have visible in them. Try using other class names or element types.
Here is a jsFiddle to get you started (ignore the window.show definition that's specific to jsFiddle).

Backbone Marionette extra div wrappers: tagName solution in other threads not working for DYNAMIC tabs

Below is a snippet from a sample tab control from here: http://layout.jquery-dev.net/demos/tabs.html
Those tabs inside those splitter panes are exactly what I need. But I need the tabs to be dynamically added and removed based on user interaction. Thought I could do it with composite or collection views in backbone marionette - add/remove things from the underlying collection and tabs appear and disappear in the UI.
Conceptually this shouldn't hard. But the difficulty comes in with the the dreaded extra wrapping div problem that is so discussed in various threads over the years.
Extra divs in itemviews and layouts in Backbone.Marionette
In my case, each li in my ul comes up wrapped in a it's own div. That messes up the CSS in the code snippet below. It breaks some of it, so things look weird. If I could just produce the output below, things wouldn't look weird.
<ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all ui-sortable" role="tablist">
<li class="ui-state-default ui-corner-top ui-tabs-active ui-state-active" role="tab" tabindex="0" aria-controls="tabs-west-1" aria-labelledby="ui-id-1" aria-selected="true">
Nunc tincidunt
</li>
<li class="ui-state-default ui-corner-top" role="tab" tabindex="-1" aria-controls="tabs-west-2" aria-labelledby="ui-id-2" aria-selected="false">
Proin dolor
</li>
</ul>
The output above has complex li's rendered directly in the ul container which is also complex. Why can't I make that output happen?
This extra wrapping div seems to be the default behavior of backbone marionette when itemView's are rendered. Many answers in these threads center on setting the tagName property to li. Problem is that produces a blank, generic li. Look at the li's in the snippet above. They have lots of properties.
My li's will need to have unique id's and styling and other attributes like those above. Making your item view's tagName an li just produces a simple li in your output. How do I get my dynamic id's and styling classes and such in there?
My first attempt to fix this was to pull the li code into my handlebars template so I could encode it with the dynamic data I needed:
var TabItemView = Marionette.ItemView.extend({
template: Handlebars.compile(
'<li class="ui-state-default ui-corner-top ui-tabs-active ui-state-active" role="tab" tabindex="0" aria-controls="tabs-{{id}}" aria-labelledby="ui-id-{{id}}" aria-selected="true">' +
'{{tabName}}' +
'</li>'
),
});
But that now wraps each li in my list in it's own container div. Every combination of using el, tagName, appendHtml override produces either a wrapping element or incorrect results - like appendHtml override causes each new tab to simply replace existing tabs - so I only ever have one tab, the latest one added.
What am I missing here? Why can't I define a template for an li containing dynamic data in it and render it DIRECTLY to my ul WITHOUT an extra wrapping div around each list element? I guess another way to phrase the question is I am working with an existing template that REQUIRES complex li's. How do I produce them in a composite or collection view WITHOUT the extra wrapping container around them?
Backbone and Marionette seem to offer the promise of being able to do things like this in a way more manageable than doing it in straight jQuery. I'm not having that experience. What am I not seeing?
I don't use Marionette, but I don't see why it would override Backbone's default behavior. This should give you an idea:
var TabView = Marionette.ItemView.extend({
tagName: 'ul',
className: 'ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all ui-sortable" role="tablist',
render: function() {
//something like this
var _this = this;
this.collection.each(function(item){
var view = new TabItemView({
model: item
});
_this.$el.append(view.render().el)
})
}
});
var TabItemView = Marionette.ItemView.extend({
tagName: 'li',
className: 'ui-state-default ui-corner-top ui-tabs-active ui-state-active" role="tablist',
template: Handlebars.compile(
'{{tabName}}'
),
});
Regarding managing views and data to produce specific HTML output, I suggest you take a look at my blog post here: http://davidsulc.com/blog/2013/02/03/tutorial-nested-views-using-backbone-marionettes-compositeview/
That should get you to structure the views so they render properly. Then, you can add http://backbonejs.org/#View-attributes to the mix to get your complex attributes (for which there aren't existing Backbone attributes such as className).