Slots ignored for CoreUI's CInput - vue.js

I guess, that I'm misunderstanding something. According to this documentation, I came up with the following prototype code to replace the old classic syntax. But it doesn't work at all.
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">
<CIcon name="cil-lock-locked" />
</span>
</div>
<input type="password"
class="form-control"
placeholder="Passwort"
:isValid="false"
invalidFeedback="hdhdh"
v-model="enteredPassword" />
</div>
<!-- ---------------------------------------------- -->
<CInput value="lll">
<prepend>ppp</prepend>
<prepend-content>
dddd
</prepend-content>
<label>
dkjdjdj
</label>
</CInput>
The bottom code just displays a complete empty text box. But why?

Slots are referenced with v-slot or # prefix. Try
<CInput value="lll">
<template #prepend>ppp</template>
<template #prepend-content>
dddd
</template>
<template #label>
dkjdjdj
</template>
</CInput>
You have used unknown custom element (and html label) instead of slot.

Related

How to use Vuetify for a Keycloak Login theme

I'm still quite new to web development, so there might be some very basic misunderstandings on my part.
What I'm trying to do:
We use Keycloak to manage access to a web app. The app is Vue project using Vuetify. To achieve a unified look, I want to use Vuetify to design the Keycloak theme for the login as well.
Here is the screendesign:
What I've done so far:
I created the folder keycloak/themes/my-theme, and added these files:
I took the two ftl files from the base theme, then I tried to rewrite the login with Vuetify classes.
To do so I inspected the code of the elements I want in the Vuetify docs and worked them into login.ftl. While this did work more or less for the Log In button, it seems to be completely wrong for the inputs.
Here is what it looks like:
The misalignment is probably fixable with a lot of fine tuning, but one thing I don't know what to do about is that the text inputs don't get activated when I click into them.
I'm pretty sure that copying code from the developer tools is the wrong way to do this. Is there any way to actually design a Keycloak theme with Vuetify? Without basically copying the Vuetify code?
Here is the current login.ftl:
<#import "template.ftl" as layout>
<#layout.registrationLayout displayInfo=social.displayInfo displayWide=(realm.password && social.providers??); section>
<#if section = "header">
${msg("loginWelcomeMessage")}
<#elseif section = "form">
<div id="kc-form" <#if realm.password && social.providers??>class="${properties.kcContentWrapperClass!}"</#if>>
<div id="kc-form-wrapper" <#if realm.password && social.providers??>class="${properties.kcFormSocialAccountContentClass!} ${properties.kcFormSocialAccountClass!}"</#if>>
<#if realm.password>
<form id="kc-form-login" onsubmit="login.disabled = true; return true;" action="${url.loginAction}" method="post">
<div class="${properties.kcFormGroupClass!}">
<div class="v-input rom__text--darkblue theme--light v-text-field v-text-field--is-booted v-text-field--enclosed v-text-field--outlined v-text-field--placeholder">
<div class="v-input__control">
<div class="v-input__slot">
<div class="v-input__prepend-inner">
<div class="v-input__icon v-input__icon--prepend-inner"><i aria-hidden="true" class="v-icon notranslate fas fa-user-circle theme--light"></i></div>
</div>
<fieldset aria-hidden="true">
<legend style="width: 188.25px;"><span>​</span></legend>
</fieldset>
<div class="v-text-field__slot">
<label for="username" class="v-label v-label--active" style="left: -28px; right: auto; position: absolute;">
${msg("usernameOrEmail")}
</label>
<#if usernameEditDisabled??>
<input tabindex="1" id="username" placeholder="Ihr Nutzername" type="text" value="${(login.username!'')}" type="text" disabled>
<#else>
<input tabindex="1" id="username" placeholder="Ihr Nutzername" type="text">
</#if>
</div>
</div>
<div class="v-text-field__details">
<div class="v-messages theme--light">
<div class="v-messages__wrapper"></div>
</div>
</div>
</div>
</div>
</div>
<div class="${properties.kcFormGroupClass!}">
<label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
<input tabindex="2" id="password" class="${properties.kcInputClass!}" name="password" type="password" autocomplete="off" />
</div>
<div class="${properties.kcFormGroupClass!} ${properties.kcFormSettingClass!}">
<div id="kc-form-options">
<#if realm.rememberMe && !usernameEditDisabled??>
<div class="checkbox">
<label>
<#if login.rememberMe??>
<input tabindex="3" id="rememberMe" name="rememberMe" type="checkbox" checked> ${msg("rememberMe")}
<#else>
<input tabindex="3" id="rememberMe" name="rememberMe" type="checkbox"> ${msg("rememberMe")}
</#if>
</label>
</div>
</#if>
</div>
<div class="${properties.kcFormOptionsWrapperClass!}">
<#if realm.resetPasswordAllowed>
<span><a tabindex="5" href="${url.loginResetCredentialsUrl}">${msg("doForgotPassword")}</a></span>
</#if>
</div>
</div>
<div id="kc-form-buttons" class="${properties.kcFormGroupClass!} align-center justify-center">
<input type="hidden" id="id-hidden-input" name="credentialId" <#if auth.selectedCredential?has_content>value="${auth.selectedCredential}"</#if>/>
<button tabindex="4" name="login" id="kc-login" type="submit" class=" align-center justify-center v-btn rom__darkblue rom__text--white elevation-2 v-size--large">
<i class="v-icon v-icon--left fas fa-sign-in-alt"></i>
${msg("doLogIn")}
</button>
</div>
</form>
</#if>
</div>
<#if realm.password && social.providers??>
<div id="kc-social-providers" class="${properties.kcFormSocialAccountContentClass!} ${properties.kcFormSocialAccountClass!}">
<ul class="${properties.kcFormSocialAccountListClass!} <#if social.providers?size gt 4>${properties.kcFormSocialAccountDoubleListClass!}</#if>">
<#list social.providers as p>
<li class="${properties.kcFormSocialAccountListLinkClass!}"> <span>${p.displayName}</span></li>
</#list>
</ul>
</div>
</#if>
</div>
<#elseif section = "info" >
<#if realm.password && realm.registrationAllowed && !registrationDisabled??>
<div id="kc-registration">
<span>${msg("noAccount")} <a tabindex="6" href="${url.registrationUrl}">${msg("doRegister")}</a></span>
</div>
</#if>
</#if>
</#layout.registrationLayout>
It looks like you are using Vuetify styles only. I would try to use Vue with the top element:
new Vue({
el: "#kc-form",
vuetify: new Vuetify(),
...
And then I would create all inputs with Vuetify, e.g. username:
<v-text-field label="Username or email" id="username" />
But you need to mimic those original HTML inputs, so you need to add also some parameters, e.g. name - I would use mounted for that - naive implementation:
mounted() {
document.getElementById("username").setAttribute("name", "username")
}
It may need also changes in the layout template and more tweaks to have naive Vuetify feel and full Keycloak functionality. It will be nice if you share your results (even incomplete) on the GitHub.
Proof of concept: https://github.com/jangaraj/vuetify-keycloak-theme/ :

How to centre text in a Buefy input box?

I have a Buefy template which looks a little like this but I cannot work out how to centre the input box text so everything looks pretty.
I've tried adding 'has-text-centered' to basically everything and it still doesn't centre it!
<template>
<section class="hero is-info is-fullheight">
<div class="hero-body">
<div class="container">
<div class="columns is-centered">
<div class="column is-5-tablet is-4-desktop is-3-widescreen">
<div class="box">
<div class="login">
<b-field label="">
<b-input type="email"
placeholder="john#doe.com"
v-model="email">
</b-input>
</b-field>
<b-field label=""
:message="error_message">
<b-input type="password"
placeholder="****************"
v-model="password">
</b-input>
</b-field>
<div class="buttons">
<b-button #click="login" :loading="loading" type="is-info" expanded>Log In</b-button>
</div>
<p>Create an account <router-link to="/sign-up">here</router-link>!</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
What am I missing here?
You could add a custom class to your input:
<b-input type="email"
placeholder="john#doe.com"
v-model="email"
class="input-text-center"
>
</b-input>
And then write a CSS for that:
.input-text-center input {
text-align: center;
}
Please note since you are writing a CSS for a Buefy module you can't do it with scoped CSS as you would normally do in a Vue single file component. Instead you should add this CSS at a more global level.

How to use Bootstrap button-group radios with Vue's v-model?

I'm using vuejs with bootstrap 4.4. Refactoring the code I'd like to move from invoking methods to using v-model (some bootstrap markup omitted for clarity). The radios button group is modeled after https://getbootstrap.com/docs/4.0/components/buttons/#checkbox-and-radio-buttons:
{{mode}}
<div class="btn-group btn-group-toggle py-4 mb-2" data-toggle="buttons">
<label>
<input type="radio" name="mode" value="off" v-model="mode">Stop</input>
</label>
<label>
<input type="radio" name="mode" value="now" v-model="mode">Sofort</input>
</label>
</div>
mode is a simple property:
data: function () {
return {
mode:"pv",
};
},
Unfortunately, after changing from the previous implementation using v-on:click="setMode(...)" to v-model, mode is never updated, no error given.
The bootstrap docs state:
The checked state for these buttons is only updated via click event on the button
Might that conflict with vuejs's v-model handling? How can I make v-model work with bootstrap radio groups?
Issue is with data-toggle property, as long as you remove it, it will work. I have tried with following and it is working, you just need to manage active class with Vue variable's value.
<div id="app">
{{mode}}
<div class="btn-group btn-group-toggle">
<label class="btn btn-secondary active">
<input type="radio" name="options" value="now" id="option1" v-model="mode" autocomplete="off" checked> Active
</label>
<label class="btn btn-secondary">
<input type="radio" name="options" value="off" id="option2" v-model="mode" autocomplete="off"> Radio
</label>
</div>
</div>

VueJS - v-model in for-loop

I'm trying to build something like the questions in OkayCupid, but all the questions - which are different forms - are located on the same component.
I use an object of questions and 3 possible answers for each question, and I use v-for to loop through the object and create cards with a question, 3 answers with radios, and a submit button.
The problem is that I want to get not only the answer the user chooses, but also the question it belongs to.
Here is my form in the template:
<div class="container">
<div class="row">
<div
class="col-lg-3 col-md-4 col-6"
v-for="(question,index) in questionCollection"
:key="index"
>
<form class="form">
<div class="img-fluid img-thumbnail shadow-lg p-3 mb-5 bg-white rounded">
<!-- <input type="text" :value="question.question" v-model="q" /> -->
<h3 class="d-block mb-4 h-100" alt data-holder-rendered="true">{{ question.question }}</h3>
<div class="card-body container">
<div class="card-text form-check">
<input
class="form-check-input"
type="radio"
name="gridRadios"
id="a1"
:value="question.answer1"
v-model="answer"
/>
<h4 class="font-weight-light" for="a1">{{ question.answer1 }}</h4>
</div>
<div class="card-text form-check">
<input
class="form-check-input"
type="radio"
name="gridRadios"
id="a2"
:value="question.answer2"
v-model="answer"
/>
<h4 class="font-weight-light" for="a2">{{ question.answer2 }}</h4>
</div>
<div class="card-text form-check">
<input
class="form-check-input"
type="radio"
name="gridRadios"
id="a3"
:value="question.answer3"
v-model="answer"
/>
<h4 class="font-weight-light" for="a3">{{ question.answer3 }}</h4>
</div>
</div>
<div class="card-text container">
<small class="text-muted">{{ question.user }}</small>
<button
href="#"
class="btn btn-primary my-3 mx-10 btn float-right shadow-sm rounded"
#click.prevent="answerQuestion"
>Save</button>
</div>
</div>
</form>
</div>
</div>
</div>
And the script:
export default {
name: "questions",
data() {
return {
q: null,
answer: null
};
},
}
As you can see, at the beginning of the form, I tried to get the question element using v-model in a "fake" input, but it gives me an error that it's conflicted with the v-bind of the value (the question) I want to grab. Of course, I can't use v-model on the headline itself because Vue allows to use it only on inputs.
I've tried to change the v-model into v-model="questionCollection[index].question, but then I have no idea how to get it in the script and, let's say, log it to the console with the corresponding answer.
One way to handle this is to submit the question and answer together in the Save button's click-handler. That is, change answerQuestion() to receive question (the iterator variable in v-for) and answer, and update the Save button's click handler in the template to pass those two variables:
// template
<div v-for="(question, index) in questionCollection">
...
<button #click.prevent="answerQuestion(question, answer)">Save</button>
</div>
// script
answerQuestion(question, answer) {
console.log({ question, answer })
}
demo

How to use conditionals without attaching it to an element?

In vue, we have got directives v-if which needs to be attached to element.
Is there a way to use conditionals without attaching them to anything like the mustachejs way?
I am looping through an array of words and it is adding div's in every word which is annoying
Here is my template
<div v-for="(str, index) in reference" :key="index">
<div v-if="patternIncluded(str)">
<input type="text" v-model="remarks[index]">
</div>
<div v-else>
{{str}}
</div>
</div>
I would be nice if i could do it like this:|
{{if true}}
something goes here
{{else}}
other thing goes here
{{\if}}
Here is your code but using the < template > tag
<template v-if="patternIncluded(str)">
<input type="text" v-model="remarks[index]">
</template>
<template v-else>
{{str}}
</template>
Here is a example from the official Vue documentation:
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
More informations: https://v2.vuejs.org/v2/guide/conditional.html#Controlling-Reusable-Elements-with-key
You can also use a Method and use normal Javascript into the < script > at the bottom of your file
Hope this helped, cheers
you could use the 'template' like so:
<template v-if=patternIncluded(str)>
//code
</template
<template v-else>
//code
</template>
UPDATE so like this
<div-for="(str, index) in reference" :key="index">
<template v-if="patternIncluded(str)">
<input type="text" v-model="remarks[index]">
</template>
<template v-else>
{{str}}
</template>
</div>