How to use image in kendo-ui-sortables angular 2 - kendo-ui-angular2

I want to use images rather than data in items, any way out there ?
import { Component, ViewEncapsulation } from '#angular/core';
#Component({
selector: 'my-app',
template: `
<div class="example-config">
<h6>Items: {{items | json}}</h6>
</div>
<div class="container-fluid">
<kendo-sortable
[navigatable]="true"
[animation] = "true"
[data]="items"
class="row"
itemClass="item col-xs-6 col-sm-3"
activeItemClass="item col-xs-6 col-sm-3 active"
>
</kendo-sortable>
</div>
`,
encapsulation: ViewEncapsulation.None,
styleUrls: ['styles.css']
})
export class AppComponent {
public items: string[] = [
'Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6', 'Item 7', 'Item 8'
];
}
Like this? any way to use it with images ?
Have a look in this, any way to use image instead of grid of data

you can use tag like this code:
<kendo-grid-column title="picture">
<ng-template kendoGridDetailTemplate let-dataItem>
<section *ngIf="dataItem.Thumb">
<img src="{{dataItem.thumb}}" />
</section>
</ng-template>
</kendo-grid-column>

You can use templates and an array of objects with a field pointing to the respective image source as data items, e.g.:
<kendo-sortable
[navigatable]="true"
[animation] = "true"
[data]="items"
class="row"
>
<ng-template let-item="item">
<div class="item">
<img [src]="item.url" [alt]="item.text" width="200" style="pointer-events: none;" />
</div>
</ng-template>
</kendo-sortable>
...
public items: any[] = [
{text: 'Img 1', url: 'https://cdn.pixabay.com/photo/2017/09/01/20/23/ford-2705402__340.jpg'},
{text: 'Img 2', url: 'https://cdn.pixabay.com/photo/2017/09/24/17/19/cow-2782461__340.jpg'}
];
EXAMPLE

Related

Set heights of a row of components dynamically based on the tallest one

I have three components called blog cards that are rendered with an image and text. Depending on how long the text is the cards are of different heights. I want to render them, then get the tallest one, and sort of re-render them, so they are all the same height.
Here is the Page
import * as React from 'react'
import { SocialIconRow } from '#/components/social-icons'
import BlogPostCard from '#/components/BlogCard'
import Image from 'next/image'
import { useState, useEffect } from 'react'
import { FixedSizeList } from 'react-window'
function BlogPostCardsList({ cards }) {
const tallestCardHeight = useMemo(() => {
return Math.max(...cards.map(card => card.height))
}, [cards])
return (
<FixedSizeList
itemCount={cards.length}
itemSize={tallestCardHeight}
width={'100%'}
height={'100%'}
>
{({ index, style }) => <BlogPostCard style={style} {...cards[index]} />}
</FixedSizeList>
)
}
export default function MyComponent(props) {
const [cardHeight, setCardHeight] = useState(null);
const [maxHeight, setMaxHeight] = useState(0);
useEffect(() => {
const calculateHeight = () => {
const cards = document.querySelectorAll('.blog-post-card');
let heights = [];
cards.forEach(card => {
heights.push(card.clientHeight);
});
setMaxHeight(Math.max(...heights));
}
calculateHeight();
setCardHeight(maxHeight);
}, []);
return (
<>
<div className="container mx-auto flex flex-col">
<div className="container mx-auto flex">
<div className="w-1/2 pr-4">
<div className="text-4xl font-bold">Mike Borman</div>
<div className="text-lg mt-2">Writer, Content Creator and Developer on Cardano</div>
</div>
<div className="w-1/2 flex flex-col justify-center">
<div className="max-h-48 max-w-48 mx-auto my-auto">
<Image
src="/images/myfaceppgray.png"
alt="Picture of the author"
className="max-h-48 max-w-48"
width="150"
height="150"
unoptimized={true}
/>
</div>
<div className="mt-4">
<SocialIconRow className="social-icon-row" />
</div>
</div>
</div>
<div className="mt-8">
<div className="text-3xl font-bold">Featured Blogs</div>
<div className="grid grid-cols-3 gap-4 h-full mt-4 align-items-stretch">
<div style={{height: cardHeight}}>
<BlogPostCard
title="The Hydra Protocol Family — Scaling and Network Optimization for the Cardano Blockchain"
slug="the-hydra-protocol-family-scaling-and-network-optimization-for-the-cardano-blockchain"
imageslug="/images/hydra.png"
className="blog-post-card"
/>
</div>
<div style={{height: cardHeight}}>
<BlogPostCard
title="Ouroboros, A deep dive for non PhDs"
slug="ouroboros-a-deep-dive-for-non-phd"
imageslug="/images/ourobouros.png"
className="blog-post-card"
/>
</div>
<div className="h-full row-auto" style={{height: cardHeight}}>
<BlogPostCard
title="Ouroboros, A deep dive for non PhDs"
slug="ouroboros-a-deep-dive-for-non-phd"
imageslug="/images/ourobouros.png"
className="blog-post-card"
/>
</div>
</div>
</div>
</div>
</>
)
}
Here is the Card component:
import React from 'react'
import Link from 'next/link'
import Image from 'next/image'
function BlogPostCard(props) {
const { title, slug, imageslug } = props
return (
<Link href={`/blog/${slug}`}>
<a className="block flex flex-col justify-between rounded-md border-2 border-teal-400 transition-all duration-300 ease-in-out hover:scale-105 hover:shadow-lg">
<img className="rounded-t-md h-48 w-full object-cover" src={imageslug} alt="blog post cover" />
<span className="text-white text-2xl p-4">{title}</span>
</a>
</Link>
)
}
export default BlogPostCard
I tried dynamically rendering them then setting them, btw I have no idea really what Im doing there.
You actually have all but one class already to do this entirely in CSS. Just add h-full to your a tag inside the BlogPostCard component's Link. Then you can get rid of all of the JS. Optionally, you could also remove the justify-between or change it to justify-stretch so that the titles of the blog posts are directly beneath of the post cover images.
In the demo below, you can see the result by clicking run code snippet. Also, if you're upgrading to NextJS 13, it's worth noting that you no longer need (and in fact can't have) an a tag as a child of Link. I'd suggest using article as I've done below, which will be more semantically correct anyway.
function BlogPage({posts}) {
return (
<main className="container mx-auto my-8">
<div className="flex gap-4">
<div className="w-1/2">
<h1 className="text-4xl font-bold">Mike Borman</h1>
<h2 className="text-lg mt-2">
Writer, Content Creator and Developer on Cardano
</h2>
</div>
<div className="w-1/2 flex flex-col justify-center items-center">
<span className="w-[150px] h-[150px] bg-neutral-300 rounded-full grid place-content-center">author img here</span>
<span>social row here</span>
</div>
</div>
<section className="mt-8">
<header>
<h2 className="text-3xl font-bold">Featured Blogs</h2>
</header>
<div className="grid grid-cols-3 gap-4 h-full mt-4 align-items-stretch">
{posts.map((post) => (
<BlogPostCard key={post.id} {...post} />
))}
</div>
</section>
</main>
)
}
function BlogPostCard({ slug, imageslug, title,}) {
return (
<Link href={`/blog/${slug}`}>
<article className="flex flex-col justify-stretch h-full rounded-md border-2 border-teal-400 bg-neutral-600 transition-all duration-300 ease-in-out hover:scale-105 hover:shadow-lg">
<img
className="rounded-t-md h-48 w-full object-cover"
src={imageslug}
alt="blog post cover"
/>
<span className="text-white text-2xl p-4">{title}</span>
</article>
</Link>
)
}
/* Stubbing out next/link here since I can't run NextJS in code snippets */
function Link({ href, children, className }) {
return (
<a href={href} className={className}>
{children}
</a>
)
}
const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<BlogPage posts={[
{
id: 1,
title: 'The Hydra Protocol Family — Scaling and Network Optimization for the Cardano Blockchain',
slug: 'the-hydra-protocol-family-scaling-and-network-optimization-for-the-cardano-blockchain',
imageslug: 'https://d3lkc3n5th01x7.cloudfront.net/wp-content/uploads/2019/05/15233606/700-X-394.png',
},
{
id: 2,
title: 'Ouroboros, A deep dive for non PhDs',
slug: 'ouroboros-a-deep-dive-for-non-phd',
imageslug: 'https://www.almaviva.it/dam/jcr:6212e8ef-1ed6-40e2-a75f-b6fa7c814662/Blockchain_1280x720.jpg',
},
{
id: 3,
title: 'How Blockchain Is Used',
slug: 'how-blockchain-is-used',
imageslug: 'https://imageio.forbes.com/specials-images/imageserve/5f2a32ee3b52675a453e2881/Fascinating-Examples-Of-How-Blockchain-Is-Used-In-Insurance--Banking-And-Travel/960x0.jpg?format=jpg&width=960',
},
]} />
);
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
<div id="root"></div>

how to output data in hbs file

index.hbs code:
This is index.hbs file where i pass data from index.js file.
```{{# each products}}
<div class="row">
{{# each this}}
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="{{imagePath}}" alt="..." class="img-responsive">
<div class="caption">
<h3>{{title}}</h3>
<p class="description">{{description}}</p>
<div class="clearfix">
<div class="price pull-left">{{price}}</div>
Button
</div>
</div>
</div>
</div>
{{/each}}
</div>
{{/each}}```
index.js code:
var products=Product.find(function(err,docs){
res.render('shop/index', { title: 'Shopping Cart', products:docs });
});
data in mongob Schema is like this
var products= [
new Product
({
imagePath:'https://upload.wikimedia.org/wikipedia/en/5/5e/Gothiccover.png',
title:'Gothic video games',
description:'Awesome Game!!',
price: 20
}),
new Product({
imagePath:'https://upload.wikimedia.org/wikipedia/en/5/5e/Gothiccover.png',
title:'Gothic video games',
description:'Awesome Game!!',
price: 20
}),
new Product({
imagePath:'https://upload.wikimedia.org/wikipedia/en/5/5e/Gothiccover.png',
title:'Gothic video games',
description:'Awesome Game!!',
price: 20
}),
new Product({
imagePath:'https://upload.wikimedia.org/wikipedia/en/5/5e/Gothiccover.png',
title:'Gothic video games',
description:'Awesome Game!!',
price: 20
}),
new Product({
imagePath:'https://upload.wikimedia.org/wikipedia/en/5/5e/Gothiccover.png',
title:'Gothic video games',
description:'Awesome Game!!',
price: 20
})
];
The result shows five empty column divs and then one column div with data. Please share its solution.
Remove the space between # and each, should be #each and NOT # each.
eg
{{#each products}}
And you DONT need 2 #each, just 1 is enough. Remove {{# each this}} as its not needed.
{{#each products}}
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="{{imagePath}}" alt="..." class="img-responsive">
<div class="caption">
<h3>{{title}}</h3>
<p class="description">{{description}}</p>
<div class="clearfix">
<div class="price pull-left">{{price}}</div>
Button
</div>
</div>
</div>
</div>
{{/each}}
So you're getting each products, and displaying its field. If you want to use 'this', then you can do eg {{this.imagePath}}, but I do believe it's not required as it works either way. You can test it yourself and it should work with, or without this, but it's easier to read as you know what it's referring to.

Cannot find control with name:

I have a quite complicated form which I want to break down into individual components. Here is my base form (only taken example fields), I'm using FormBuilder:
ngOnInit() {
this.predictorQuestion = this.fb.group({
question: ['', Validators.required],
options: this.fb.array([
this.fb.control('', Validators.required),
]),
meta_options: this.fb.group({
test_type: ['', Validators.required],
})
});
get meta_options() {
return this.predictorQuestion.get('meta_options') as FormGroup;
}
get options() {
return this.predictorQuestion.get('options') as FormArray;
}
If I try to connect this to my templates, it works perfectly:
<form [formGroup]="predictorQuestion" fxLayout="column">
<mat-form-field fxFlex appearance="outline">
<mat-label>Question</mat-label>
<input matInput formControlName="question">
</mat-form-field>
<div fxLayoutAlign="space-between center">
<h3>Options</h3>
<button (click)="addOption()" matTooltip="Add option" matTooltipPosition="right" mat-mini-fab type="button">
<mat-icon>add</mat-icon>
</button>
</div>
<div formArrayName="options" fxLayout="column">
<div *ngFor="let answer of options.controls; let i = index" fxLayout="row" fxLayoutAlign="space-between stretch">
<mat-form-field appearance="outline" fxFlex>
<mat-label>Option {{ i+1 }} </mat-label>
<input fxFlex matInput [formControlName]="i">
</mat-form-field>
<button mat-icon-button matTooltip="Remove this option" matTooltipPosition="right" (click)="removeOption(i)">
<mat-icon>close</mat-icon>
</button>
</div>
</div>
<div formGroupName="meta_options" fxLayoutAlign="space-between" fxLayoutGap="20px" fxLayout="column">
<mat-form-field fxFlex="25">
<mat-select formControlName="test_type">
<mat-option *ngFor="let vtype of vtypes" value="{{ vtype.value }}">{{ vtype.name }}</mat-option>
</mat-select>
</mat-form-field>
</div>
</form>
This renders without any errors.
If I try to break down the meta_options.test_type in a component of its own in a way like:
component.ts
#Input() parent_form: FormGroup;
public vtypes: Array<Object>;
constructor(private fb: FormBuilder) {
this.vtypes = [
{
name: 'Timestamp',
value: 'timestamp'
},
{
name: 'Over',
value: 'over'
}
];
}
component.html
<mat-form-field fxFlex="25" [formGroup]="parent_form">
<mat-select formControlName="test_type">
<mat-option *ngFor="let vtype of vtypes" value="{{ vtype.value }}">{{ vtype.name }}</mat-option>
</mat-select>
</mat-form-field>
and using this component in my main parent form as
<meta-option-value [parent_form]="predictorQuestion"></meta-option-value>
I get the following error:
"Cannot find the control with the name: 'test_type'"
What am I missing here?
You are passing the complete FormGroup (predictorQuestion) to the child. You only need to pass the predictorQuestion.get('meta_types') to the parent_form as [parent_form]="predictorQuestion.get('meta_types')".
pass the "control" itseft and use [FormControl] in your children
<meta-option-value [formControl]="predictorQuestion.get('meta_options')">
</meta-option-value>
Your meta-options
<mat-form-field fxFlex="25" [formControl]="formControl">
...
</mat-form-field>
//and add the Input
#Input()formControl: FormControl;
the same idea work if you need to pass a FormGroup or a Form Array
You can say your child component to use formControlName="test_type" depending on parent container regardless container's type(FormGroupName, FormGroup orr FormArray) by defining viewProviders:
meta-option-value.component.ts
#Component({
selector: 'meta-option-value',
template: `
<mat-form-field fxFlex="25">
<mat-select formControlName="test_type">
<mat-option ...>{{ vtype.name }}</mat-option>
</mat-select>
</mat-form-field>
`,
viewProviders: [{
provide: ControlContainer,
useFactory: (container: ControlContainer) => container,
deps: [[new SkipSelf(), ControlContainer]],
}]
})
export class MetaOptionValueComponent {
...
}
parent.template.html
<div formGroupName="meta_options">
/\
||
will look at this group
<meta-option-value></meta-option-value>
</div>
As you can see MetaOptionValueComponent contains only its own related logic.
Stackblitz Example
See also:
Angular2 nested template driven form
Of course, another way is passing FormGroup or FormControl instance and use it directly as suggested in other answers

Vue2 v-show validate empty strings in a loop

How do I validate inside of a loop with v-show empty items with vuejs2. I was trying the following but without any results
<div v-for="user in $store.state.users.data">
<ul>
<li v-show="user.mobil !== null || user.mobil !== ''" >
<a v-bind:href="'tel://' + user.mobil"> <i class="fa fa-mobile-phone"></i> <span>{{ user.mobil }} </span></a>
</li>
</ul>
</div>
Compare like v-show="user.mobil":
new Vue({
el: '#app',
data: {
users: [{
mobil: '123',
name: 'Foo'
},
{
mobil: '',
name: 'Bar'
},
{
mobil: null,
name: 'Baz'
},
]
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<div v-for="user in users">
<ul>
<li v-show="user.mobil">
{{user.name}}
</li>
</ul>
</div>
</div>
How do you check for an empty string in JavaScript?

Vue.js - Working with Components

I am new to Vue.js. Very new so this question might sound a lot like a first graders. Forgive me.
I have the App.vue and Character.vue setup. I wanted to create characters on the fly and add them to an array (in App.vue) and let the rendering of the look/feel of the characters be done using Character.vue. The characters are created and added to the array and can be retrieved properly. Only thing is...Character.vue doesn't render them properly because for some reason, the character it retrieves from the array is undefined.
Help me?
Attaching files
App.vue
<template>
<div>
<div class='gameHeader'>
<h1>{{ gameHeader }}</h1>
</div>
<div class='gameMessages'>
<div class='gameMessage' v-for="msg in gameMessages">
{{ msg }}
</div>
</div>
<div class='gameMain'>
<button #click="rollNewCharacter">Roll New</button>
<div class="playerParty">
<character v-for="p in playerParty"></character>
</div>
<div class="computerParty">
<character v-for="c in computerParty"></character>
</div>
</div>
<div class='gameFooter'>
{{ gameFooter }}
</div>
</div>
</template>
<script>
import Character from "./assets/components/Character.vue";
export default {
components: { 'character': Character },
data: function(){ return { gameHeader: 'Monster Attack', gameMessages:[], playerParty: [], computerParty: [], gameFooter: '' }; },
methods: {
rollNewCharacter() {
var c = Character;
c.name = 'Usman';
c.type = 'Warrior';
c.mana = 100;
c.health = 100;
c.totalHealth = 100;
c.totalMana = 100;
console.log(c.name);
this.playerParty.push(c);
console.log(this.playerParty[0].name);
//this.computerParty.push(chr2);
}
}
}
</script>
Character.vue
<template>
<div class="character">
<span class='name'>{{ name }}</span><span class='type'>({{ type }})</span>
<div class='health'><div class='total' :class="totalHealth"><div class='health' :class="health"></div></div></div>
<div class='mana'><div class='total' :class="totalMana"><div class='mana' :class="mana"></div></div></div>
<span class='damage'>{{ damage }}</span>
<div class="actions">
<button #click="attack">Attack</button>
<button #click="specialAttack">Special Attack</button>
<button #click="heal">Heal</button>
</div>
</div>
</template>
<script>
export default {
props: [ 'name', 'type', 'mana', 'health', 'damage' , 'totalHealth', 'totalMana' ],
methods: {
attack: function(){},
specialAttack: function(){},
heal: function(){ alert(this.name); console.log(this);}
}
}
</script>
<style>
</style>
You should pass a prop when using the character component:
<character :character="p" v-for="p in playerParty"></character>
I have updated the character to receive only one prop:
export default {
props: [ 'character' ],
methods: {
attack: function(){},
specialAttack: function(){},
heal: function(){ alert(this.name); console.log(this);}
}
}
And this is the character component template with the new prop:
<template>
<div class="character">
<span class='name'>{{ character.name }}</span><span class='type'>({{ character.type }})</span>
<div class='health'><div class='total' :class="character.totalHealth"><div class='health' :class="character.health"></div></div></div>
<div class='mana'><div class='total' :class="character.totalMana"><div class='mana' :class="character.mana"></div></div></div>
<span class='damage'>{{ character.damage }}</span>
<div class="actions">
<button #click="attack">Attack</button>
<button #click="specialAttack">Special Attack</button>
<button #click="heal">Heal</button>
</div>
</div>
</template>

Resources