How do you change a class when a button is clicked in Svelte? - class

How do you change a class when a button is clicked in Svelte?
The code is here:
<script lang="ts">
let rank = 1;
const changeRank = () => {
if (rank == 1) {
rank = 2
} else {
rank = 1
}
};
</script>
<main>
<div class="card" class:input-focus={rank === 1? "rank-1" : "rank-2"} />
<button on:click={changeRank}>Change Rank</button>
</main>

You are using a class directive (class:...), this will add the class after the : if the value is truthy. This is probably not what you want here, because both values are truthy so it will always add the class input-focus.
You probably meant to do something like this:
<div class="card {rank === 1 ? 'rank-1' : 'rank-2'}" />
If all classes have that prefix you could just do this as well:
<div class="card rank-{rank}" />

Related

how to return computed html in vue2?

I try to return the part of html depending on variable type I want to do like:
<template>
<div>{{getvalue(this.$store.state.output)}}</div>
</template>
<script>
export default {
methods:{
getvalue(output){
if(output.constructor == Array){
re="";
for(i in output){
re+=<p>{{i}}</p>;
}
return re;
}
else if(output.constructor == Object){
re="";
for(i in output){
re+=<p><span>i</span><span>{{output[i]}}</span></p>
}
return re;
}else if(output.constructor == String){
return <p>{{output}}</p>
}
}
},
...
}
</script>
I know in react I can use virtualDOM to do that, how should I do the similar things like above in Vue2.5.11?
#ceejayoz is right. It would be missing the whole point of Vue.
Another mistake is that computed values don't accept parameters. It is supposed to be treated as a value and not a function.
This is a more proper way of doing things in Vue. By using v-if and v-for.
<template>
<div>
<div v-if="getOutputConstructor==Array">
<p v-for="i in this.$store.state.output" :key="i">{{i}}</p>
</div>
<div v-else-if="getOutputConstructor==Object">
...
</div>
<div v-else-if="getOutputConstructor==String">
...
</div>
</div>
</template>
<script>
export default {
computed: {
getOutputConstructor() {
const output = this.$store.state.output;
return output.constructor;
}
}
};
</script>
But.. if you really really want to do it the wrong way, use v-html

angular 2, validate form if at least one input is typed

I'm quite new to Angular, and I've already searched the web, without finding a correct solution for my situation.
I have a dynamic form created by a *ngFor. I need to disabled the submit button if the inputs are all empty and show the alert div; but I need to enable the submit if at least one of those forms contains something different from ''.
Here is my html code
<form class="form-inline" #form="ngForm">
<div class="form-group" *ngFor="let meta of state.metaById; let i = index" style="margin: 5px">
<label>{{meta.nome}}</label>
<input type="text" class="form-control" #nome (blur)="inputInArray(nome.value, i);">
</div>
<button type="button" class="btn btn-primary" (click)="getCustomUnitaDocumentaliRow(this.param)" [disabled]="fieldNotCompiled">invia</button>
</form>
<div class="alert-notification" [hidden]="!fieldNotCompiled">
<div class="alert alert-danger">
<strong>Va compilato almeno un campo.</strong>
</div>
</div>
and here is my Typescript code
inputInArray(nome: string, indice) {
if (this.state.controlloMetaId = true) {
this.state.metadatoForm[indice] = nome;
}
// this.fieldNotCompiled = false;
for (const i in this.state.metaById) {
console.log(this.state.metadatoForm);
if (isUndefined(this.state.metadatoForm[i]) || this.state.metadatoForm[i] === '') {
this.fieldNotCompiled = true && this.fieldNotCompiled;
} else {
this.fieldNotCompiled = false && this.fieldNotCompiled;
}
console.log(this.fieldNotCompiled);
}
With this code I can check the first time a user type something in one input, but it fails if it empty one of them (or all of them)
Thanks for your time
UPDATE
Check if any input got a change that is different from empty or space, just by doing:
<input ... #nome (input)="fieldNotCompiled = !nome.value.trim()" ....>
DEMO
You can set a listener to the form changes:
#ViewChild('form') myForm: NgForm;
....
ngOnInit() {
this.myForm.valueChanges.subscribe((value: any) => {
console.log("One of the inputs has changed");
});
}

Can I autofocus on the first field in a redux-form created using a loop?

I have created a React component using redux-form and am looking to autoFocus on the first field. The fields are created by looping through an object and creating a field for each item in that object. When I use autoFocus in the JSX is autoFocuses on the last field in the form (which makes sense).
Does anyone know how I can autoFocus on the first field in the form?
Here is my component:
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
class BalanceForm extends Component {
constructor(props) {
super(props);
this.submitForm = this.submitForm.bind(this);
this.cancel = this.cancel.bind(this);
}
cancel() {
//not relevant
}
submitForm(e, values) {
//not relevant
}
render() {
return (
<div>
{this.props.balanceFormVisible &&
<div className="modal-background">
<div className="modal">
<form onSubmit={this.submitForm}>
{Object.keys(this.props.accounts).map((key) => {
return (
this.props.accounts[key].visible &&
<div key={this.props.accounts[key].name}>
<label className="form-label" htmlFor={this.props.accounts[key].name}>
{this.props.accounts[key].display}
</label>
<Field
name={this.props.accounts[key].name}
component="input"
type="number"
placeholder=""
autoFocus
/>
</div>
)
})}
<button type="submit">Submit</button>
<button onClick={ this.cancel } className="cancelbtn" >Cancel</button>
</form>
</div>
</div>
}
</div>
);
}
}
BalanceForm = reduxForm({form: 'balance'})(BalanceForm)
export default BalanceForm;
Thanks in advance :)
Solution to this was to conditionally render the form field. Thanks to Alexander Borodin for the inspiration...
{Object.keys(this.props.accounts).map((key, i) => {
console.log(key, i)
return (
this.props.accounts[key].visible &&
<div key={this.props.accounts[key].name}>
<label className="form-label" htmlFor={this.props.accounts[key].name}>
{this.props.accounts[key].display}
</label>
{(i === 0) ? (
<Field
name={this.props.accounts[key].name}
component="input"
type="number"
placeholder=""
autoFocus
/>
) : (
<Field
name={this.props.accounts[key].name}
component="input"
type="number"
placeholder=""
/>
)}
</div>
)
})}
Some of these either didn't compile or are a bit verbose. This worked for me:
{Object.keys(item)
.map((key, i) =>
<div className={`form-row ${key}`} key={key}>
<label>{key}</label>
<input value={item[key]}
type='text'
onChange={e => {
this._updateValue(key, e.target.value);
}}
autoFocus={i === 0}
/>
</div>
)}
Alternatively, if you hook in to ComponentDidMount, you can ask the DOM to focus the first existing field within the form.
Add a ref to the form
<form onSubmit={this.submitForm} ref='form'>
Use the ref to focus the element after mounting
componentDidMount() {
const firstInput = this.refs.form.querySelector('input')[0];
firstInput && firstInput.focus();
}
Try this:
{Object.keys(this.props.accounts).map((key, i) => {
return (
this.props.accounts[key].visible &&
<div key={this.props.accounts[key].name}>
<label className="form-label" htmlFor={this.props.accounts[key].name}>
{this.props.accounts[key].display}
</label>
<Field
name={this.props.accounts[key].name}
component="input"
type="number"
placeholder=""
{ (i === 0) ? 'autoFocus': ''}
/>
</div>
)
})}
I ran into an issue where autoFocus wasn't properly passing down from Field to the underlying component. Had to explicitly pass autoFocus in the props prop for Field.

react rerendering form causes focus/blur issue on state change

I have a form in a react component that has two change handlers, one for my two draftjs textareas, and one for my other text inputs:
onChangeEditor = (editorStateKey) => (editorState) => {
this.setState({ [editorStateKey]: editorState });
}
handleInputChange(event) {
event.preventDefault();
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
In my render method I have two views that I switch between depending on which view mode I am in, read or edit:
render () {
const Editable = () => (
<div className="editor">
<form className="editor-inner">
<h3>Redigerar: Anbudsbrev</h3>
<h4>Rubrik</h4>
<input type="text" key="text01" name="title" defaultValue={this.state.title} onBlur={this.handleInputChange} />
<h4>Text 1</h4>
<RichEditor editorState={this.state.editorState1} onChange={this.onChangeEditor('editorState1')} name="text01"/>
<h4>Citat</h4>
<input type="text" key="text02" name="quote01" defaultValue={this.state.quote01} onBlur={this.handleInputChange} />
<h4>Text 2</h4>
<RichEditor editorState={this.state.editorState2} onChange={this.onChangeEditor('editorState2')} name="text02" />
<EditorFooter {...this.props} submitForm={this.saveForm} />
</form>
</div>
);
const Readable = () => (
<div>
<h1 className="header66">{this.state.title}</h1>
<div className="text66">{this.state.text01}</div>
<div className="quote100">{this.state.quote01}</div>
<div className="text66">{this.state.text02}</div>
</div>
);
return (
<div>
{ this.props.isInEditMode ? <Editable /> : <Readable /> }
</div>
);
}
When I switch between inputs in my browser I have to click twice in order to get the focus on the right input.
I suspect that this is because a change is triggered on the "blur" event of each input, causing the form to rerender because state is changed. And when the form rerenders, it goes through the { this.props.isInEditMode ? <Editable /> : <Readable /> } which causes the input to lose focus.
The problem is that I don't know how to get around this.
I solved it myself.
It turns out that it was not a good idea to place the Editable and Readable inside of my component as I did. Instead I moved them out to their own components, and it works properly now.
class Editable extends React.Component {
render() {
return (
<div className="editor">
<form className="editor-inner">
<h3>Redigerar: Anbudsbrev</h3>
<h4>Rubrik</h4>
<input type="text" name="title" defaultValue={this.props.title} onChange={this.props.handleInputChange} />
<h4>Text 1</h4>
<RichEditor editorState={this.props.editorState1} onChange={this.props.onChangeEditor('editorState1')} name="text01" />
<h4>Citat</h4>
<input type="text" name="quote01" defaultValue={this.props.quote01} onChange={this.props.handleInputChange} />
<h4>Text 2</h4>
<RichEditor editorState={this.props.editorState2} onChange={this.props.onChangeEditor('editorState2')} name="text02" />
<EditorFooter {...this.props} submitForm={this.props.saveForm} />
</form>
</div>
);
}
};
class Readable extends React.Component {
render() {
return (
<div>
<h1 className="header66">{this.props.title}</h1>
<div className="text66">{this.props.text01}</div>
<div className="quote100">{this.props.quote01}</div>
<div className="text66">{this.props.text02}</div>
</div>
);
}
};

WinJS Repeater and ms-grid: Add ms-grid-row value with JavaScript

I have a series of divs which are displayed as an -ms-grid. These are outputted using the WinJS.UI.Repeater object.
I need to assign the -ms-grid-row value for the current iteration dynamically.
How would I go about doing this?
Repeater
<div data-win-control="WinJS.UI.Repeater" data-win-options="{template: select('.template')}">
</div>
Repeater Template
<div class="template" data-win-control="WinJS.Binding.Template">
<div class="col1" style="-ms-grid-row:"></div>
<div class="col2" style="-ms-grid-row:"></div>
<div class="col3" style="-ms-grid-row:"></div>
<div class="col4" style="-ms-grid-row:"></div>
</div>
CSS
.grid {
display: -ms-grid;
-ms-grid-columns: (1fr)[4];
-ms-grid-rows: (auto)[1000];
}
.grid .col1 {
-ms-grid-column: 1;
}
.grid .col2 {
-ms-grid-column: 2;
}
.grid .col3 {
-ms-grid-column: 3;
}
.grid .col4 {
-ms-grid-column: 4;
}
Because there could be up to 1000 rows, I need to assign the style inline like this:
Rendered Markup
<div class="col1" style="-ms-grid-row: 1">test</div>
<div class="col2" style="-ms-grid-row: 1">test</div>
<div class="col3" style="-ms-grid-row: 1">test</div>
<div class="col4" style="-ms-grid-row: 1">test</div>
<div class="col1" style="-ms-grid-row: 2">test</div>
<div class="col2" style="-ms-grid-row: 2">test</div>
<div class="col3" style="-ms-grid-row: 2">test</div>
<div class="col4" style="-ms-grid-row: 2">test</div>
But I have no idea how to do this inside the repeater?
Many thanks
Chris
You could try using a converter function like explained here:
http://msdn.microsoft.com/en-us/library/windows/apps/br229809.aspx
for example you can assign a function to the colour of a span and calculate that colour in a function:
<span id="loginName"
data-win-bind="innerText: name; style.color: userType LoginData.userTypeToColor">
</span>
...
WinJS.Binding.processAll(document.getElementById("loginDisplay"), LoginData.login);
WinJS.Namespace.define("LoginData", {
//Data Object
login : { name: "myname", id: "12345678", userType: "admin" },
//Converter function
userTypeToColor: WinJS.Binding.converter(function (type) {
return type == "admin" ? "Green" : "Red";
})
});
I did not test this code with the -ms-grid-row property, but it is worth a try.