Append index dynamically to attribute - javascript

I have this button element:
<button v-on:click="changeRecord(element)" v-b-modal.modal-5>Aendern</button>
it is generated dynamically inside a v-for loop.
Instead of hard coding the attribute name like above v-b-modal.modal-5 I want to concatenate it like this:
v-b-modal.modal-{{index}}
Is there a way to do this?
I'm using vue-cli 3 and bootstrap-vue.

I haven't used this framework before but looking at the second example from the docs I think something like the following should work.
<button v-on:click="changeRecord(element)" v-b-modal="`modal-${index}`">Aendern</button>
You will need to ensure that the variable index is made available when you set up the v-for
EDIT: For clarity, the above works because in VueJS the input to a directive is evaluated as an expression. The above example uses backticks string interpolation but the same can be done using pretty much any valid expression like "'modal-'+index" or based on some property on the item we are looping over "`modal-${item.id}`".
Unlike directives, class or other attributes are interpreted as plain strings unless they are bound using v-bind in which case they are treated as expressions. The example in the docs uses a simple string as an input so it's hard to tell from that particular example that it can be used in this way.

It is possible to add dynamic attributes like following
<p class="text" v-bind="options">{{ message }}</p>
Inside the computed, define the value for options
export default {
data:()=> {
return {
message: 'Hello world!',
id: 12345
}
},
computed: {
options() {
return {
[`v-b-modal.modal-${this.id}`]: "whatever"
}
}
}
}

Related

React: Return Statement

So I was reading on the Internet that
The vanilla JavaScript rule is, a return statement can only return one thing.
That one thing can be an array, an object, or React's >JSX case, a that contains multiple DOM elements.
Which Makes sense but then on the same place it was mentioned that
return [ ... cannot include a CSS class, style, an HTML attribute, ... but,
return <div classname="myClass" style={‌{color:"red"}} onClick={ ... }><p>A</p><p>B ...
can include a CSS class, style, an HTML attribute.
This statement is being little to confusing for me to understand.
"return [ ... cannot include a CSS class, style, an HTML attribute, ..."
[Question]: Can someone explain the above statement with example?
Also, this is a valid statement which we use in tutorial
return [
<p onClick={this.props.click}> Hey, I am {this.props.name}{this.props.children} and my age is {this.props.age} </p>,
<input type="text" onChange={this.props.changed} value={this.props.name} />
]
I guess we haven't used any html attribute above? but if we pass CSS class, or an HTML attribute such src or href, it won't work?
In JSX, return <someHtmlElement attribute='...'> is just a fancy syntax for a React.createElement('someHtmlElement... call, so essentially, you are still returning an object. Or, in case of your example return [ <p onClick...: an array of objects.
Also bear in mind that CSS class, style and HTML attributes only make sense in the context of an HTML element (simply put, between a < and a >), as those will all become part of the React.createElement call mentioned above. So this is why you can't directly return them in an array (i.e. return [ classname="myClass", style={‌{color:"red"}} ]): they don't have a meaning in "plain" JavaScript.
You can, however, return an array of HTML elements (which are essentially objects to JavaScript in this case), and those HTML elements of course can have CSS class, style and HTML attributes.
I hope this clears it up. When in doubt, just bear in mind that JSX simply ends up being JavaScript in the end, and try to think about what "vanilla" JavaScript would allow you to do.
what you see is 'jsx', a new syntax which came about when react was introduced. jsx looks like html, but gets converted to normal javascript function calls. You cannot use a file containing jsx and feed it to the browser. You will need some converter who converts the jsx code inside your file to javascript function calls. babel is the most famous converter of them all.
For e.g.
<div className='main' style={{backgroundColor: 'red'}}>abc</div>
gets converted to
React.createElement(
'div',
{ className: 'main', style: { backgroundColor: 'red' } },
'abc'
);
So, in your original question, what you are returning is not css properties or html, but whatever is returned by the function call React.createElement(). What does React.createElement return? It returns a plain javascript object. That object describes the html which has to be rendered. From your questions point of view, you are actually return an object.
And in your last example, therefore, you are returning an array of objects.
return [
<p onClick={this.props.click}> Hey, I am {this.props.name}{this.props.children} and my age is {this.props.age} </p>,
<input type="text" onChange={this.props.changed} value={this.props.name} />
]
P.S. You can check what javascript code your jsx will convert to here - https://babeljs.io/repl/
There is a strong difference between plain javascript syntax and React syntax. React use a syntax called JSX which thanks to compilers as Babel it is tanspiled JSX code in javascript.
To give you a better idea on what Babel does with JSX:
return [ <p />, <p className="hello" /> ];
it becomes:
return [React.createElement("p", null), React.createElement("p", { className: "hello" })];
You could visit https://babeljs.io/repl/ and see how transpiling works.

Angular 5 Component Selector in variable returning string instead of component content

I have some data that contains the selector of a component:
{
label: 'This is a label',
componentSelector: '<app-mycomponent></app-mycomponent>'
}
In my app.component.html
Instead of doing this (for example):
<div>
<app-mycomponent></app-mycomponent>
</div>
I would like to do this:
{{data.componentSelector}}
At the moment when I try this it's returning a string instead of replacing it with the contents of the component.
How can I do this?
You cannot interpolate a component, because it is made up of typescript, html, and css. it has to compile to be displayed, if you think about it, it makes sense.
On another note, even if you could interpolate, it would be a poor Angular Pattern, and could have unexpected outcomes especially in production. Stick to the best practices.

Call component dynamically via string in Ember.js

I want to invoke a component via string. The reason is that I have on my DB a text and within that text I have some keys that I want to invoke a component in case they are listed in my app.
I know there is a {{component}} helper to invoke components dynamically and I was wonder if could make use here somehow. The example I will post is trivial, but the idea is use more complex components like ember-light-table, for example.
Example:
// my-route.hbs
{{my-special-component text=complexString}}
// my-route.js
// the content of the string is never the same, which means the dynamic helpers won't be the same, nor will be at the same place.
let complexString = "This is my complex string {{my-simple-helper text="this will be bold"}}. Etc, etc...";
// my-special-component.hbs
{{formatted}}
// my-special-component.js
formatted: computed('text', function() {
// ??
})
The output would be:
This is my complex string <b>this will be bold</b>. Etc, etc...
I've tried using triple brackets but that is only for < tags >.
What if you just made a component that takes a block?
{{my-special-component}}
This is my complex string {{my-simple-helper text="this will be bold"}}. Etc, etc...
{{/my-special-component}}
and the template for that would look like:
To show above your complex string
{{yield}}
to show below your complex string

How to use Angular structural directive with multiple inputs

I want to implement something similar with angular-permisssion. And with requirement to control the element's existance, I need to use angular structural directive.
At the beginning, i think such syntax would work:
<h2 *permissionIf [permissionIfExcept]="'Read'">Except</h2>
However, it doesn't work that way.
Moreover, the offical guide only teach you how to write custom structural directive with single input.
With multi-inputs, some third-party tutorials involve a bit. But that's using the angular template micro-syntax to achieve data binding. Then one problem occurs:
template syntax doesn't support pure key-value inputs:
<h2 *permissionIf="except: map.except;only: 'test'">Except</h2>
It expands into this(which is illegal):
<h2 template="permissionIf except: map.except;only: 'test'">Except</h2>
A stupid temporary solution is add a useless variable declaration.
<h2 *permissionIf="let i;except: map.except;only: 'test'">Except</h2>
Another inconvenient way is to use template element to wrap the code.
<template permissionIf [permissionIfExcept]="'Read'">
<h2>Except</h2>
</template>
The above all are not accepetable enough. But I can't find a bette way to resolve it.
Hope some guys can give some suggestion:).
The input names need all to be prefixed with the selector of the directive, followed by the input name capitalized (i.e. permissionIfExcept). Example:
#Directive({
selector: '[permissionIf]'
})
export class PermissionIfDirective implements AfterContentInit {
private _permissionIf:string[];
#Input()
set permissionIf(value: string[]) {
this._permissionIf=value;
console.log('permissionIf: ', value);
}
private _except:string;
#Input()
set permissionIfExcept(value: string) {
this._except = value;
console.log('except: ', value);
}
}
To use them with the '*' syntax:
<div *permissionIf="permissions;except:'Read'"></div>
Note here you're using the name following the prefix uncapitalized (i.e. except). Also note the : in the assignment.
The explicit syntax (using template) would look like this:
<template [permissionIf]="permissions" [permissionIfExcept]="'Read'">
</div></div>
</template>
but with <ng-container> it could look like
<ng-container *permissionIf="permissions;except:'Read'">
<div></div>
</ng-container>
Plunker example
See also the source of NgFor as an example.
#Günter Zöchbauer answer is almost correct.
Actually right now to make his answer working you need to explicitly rename the secondary #Input name.
So it should be:
#Input("permissionIfExcept")
set permissionIfExcept(value: string) {
this._except = value;
console.log('except: ', value);
}
Then one problem occurs: template syntax doesn't support pure key-value inputs:
True
A stupid temporary solution is add a useless variable declaration.
I think you are using this in a way it was not meant to be.
From the docs:
The microsyntax parser title-cases all directives and prefixes them with the directive's attribute name, such as ngFor. For example, the ngFor input properties, of and trackBy, become ngForOf and ngForTrackBy, respectively. That's how the directive learns that the list is heroes and the track-by function is trackById.
https://angular.io/guide/structural-directives#microsyntax-examples
Bottom line is in the context of your question, the microsyntax accepts "expression", followed by optional "keyed expression"s and I'm afraid those are your only options.
One could of course pass an object as the first expression—similar to ngIf—, the difference being you can teach your directive how to evaluate the expression:
*permissionIf="{ only: 'whatever', except: ['things', 'stuff'] }"

expression inside ng-class

I have a very simple Angular App and I'm trying to use ng-repeat in conjunction with ng-class to repeat a template and apply a different class to the outer div depending on one of the properties of the data being bound.
this worked when I used a simple...
ng-class="message.type"
...but unfortunately I need to concatenate a string to the start of the message type.
I tried to create a JSfiddle here...
http://jsfiddle.net/XuYGN/5/
... but it's my first attempt at making a JSfiddle too and I must be doing something wrong because the Angular stuff doesn't seem to be running. It does show what I'm trying to do with the expression though.
Any help would really be appreciated.
html :
<div ng-controller="mainCtrl">
<div ng-repeat="message in data.messages" ng-class="'className-' + message.type">
Repeat Me
</div>
</div>
</div>
javascript :
var mainCtrl=function($scope) {
$scope.data = {}
$scope.data.messages = [
{
"type": "phone"},
{
"type": "email"},
{
"type": "meeting"},
{
"type": "note"}
]
}​
in the fiddle you put some {{}} around the expression dont do it because it is an expression.
FYI, an alternative to what #camus answered:
class="{{'className-' + message.type}}"
When using class, the expression (inside {{}}s) must evaluate to a string of space-delimited class names.
When using ng-class, the expression must evaluate to one of the following:
a string of space-delimited class names, or
and array of class names, or
a map/object of class names to boolean values.

Categories

Resources