I want to create some UI from Binding.scala. The UI contains a textbox. When the user type text in the textbox, I want to change the background color according to the user input.
import com.thoughtworks.binding._, Binding._
import org.scalajs.dom._
#dom def render = {
val color = Var("")
val styleText: String = s"background-color: ${color.bind}"
// <div> and <input> will be recreated once data changes.
<div style={styleText}>
<input id="myInput" type="text" oninput={ _: Any => color := myInput.value }/>
</div>
}
dom.render(document.body, render)
The example runs on ScalaFiddle.
However, when I enter something in the textbox, the textbox misses focus and still keep empty.
How can I fix it?
Maybe you defined the <input ...> and .bind in the same #dom method and the <input ...> is after .bind. Try to refactor the .bind and <input ...> into separate #dom methods or let the .bind expression nested in another DOM.
For example, if myInput is written before .bind, it will not be recreated:
import com.thoughtworks.binding._, Binding._
import org.scalajs.dom._
#dom def render = {
val color = Var("")
val myInput = <input id="myInput" type="text" oninput={ _: Any => color := myInput.value }/>
val styleText: String = s"background-color: ${color.bind}"
// <div> will be recreated once data changes.
// <input> will not be recreated.
<div style={styleText}>
{myInput}
</div>
}
dom.render(document.body, render)
The above example runs on ScalaFiddle.
If the .bind expression is embedded in a XHTML literal, it will not affect its children:
import com.thoughtworks.binding._, Binding._
import org.scalajs.dom._
#dom def render = {
val color = Var("")
// <div> and <input> will not be recreated when data changes.
// Only the class attribute will be changed.
<div style={s"background-color: ${color.bind}"}>
<input id="myInput" type="text" oninput={ _: Any => color := myInput.value }/>
</div>
}
dom.render(document.body, render)
The above example runs on ScalaFiddle.
Another approach is wrapping .bind expression in a #dom val:
import com.thoughtworks.binding._, Binding._
import org.scalajs.dom._
#dom def render = {
val color = Var("")
#dom val styleText: Binding[String] = s"background-color: ${color.bind}"
// <div> and <input> will not be recreated when data changes.
// Only the class attribute will be changed.
<div style={styleText.bind}>
<input id="myInput" type="text" oninput={ _: Any => color := myInput.value }/>
</div>
}
dom.render(document.body, render)
The above example runs on ScalaFiddle.
Related
I want to use Binding.scala in my Github Pages.
The Problem I have is that the value that I bind is not updated.
Here the example:
val radiusVar = Var(3.0)
#dom
private lazy val plotly: Binding[HTMLElement] = {
val radiusVal = radiusVar.bind
println(s"new radius: $radiusVal") // this part is not executed after updating the radiusVar
<div class="ui form">
<div class="field">
<label>Radius</label>
<input type="text" name="radius" id="radius" value={
radiusVal.toString
}/>
</div>
<button class="ui button"
onclick={
_: Event =>
println("radius.value: " + radius.value) // this works
radiusVar.value = radius.value.toInt
}>Submit</button>
</div>
}
Whenever changing the radius, I expect that println(s"new radius: $radiusVal") is executed.
It works in ScalaFiddle from Yang Bo: https://scalafiddle.io/sf/PET64Sz/1
The rendered Page: Github Pages
The whole project: Github
The problem was that I included the ..-fastopt-bundle.js more than ones.
It looks like the second action was called on the other "JavaScript".
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");
});
}
Several days ago I read about binding.scala and I found it so cool therefore I decided to write my own single page app.
The problem is that I'm trying to add "li" items into "ul" element, but it seems like the component Want doesn't see updates.
The code below:
case class Movie(title: Var[String], raring: Var[Int], watched: Var[Boolean])
var movies = Vars.empty[Movie]
#dom def Want = {
println(movies.bind, "!##!##!##!")
<div class="want">
<ul>
{for (movie <- movies.value) yield {
<li>
<div>
<span>
{movie.title.bind}
</span>
<button onclick={event: Event => {
event.preventDefault()
movies.value.remove(movies.value.indexOf(movie))
println(movies.value)
}}></button>
</div>
</li>
}}
</ul>
</div>
When I change movies nothing happens.
UPDATE
After the comment below I updated the code:
def remove(movie:Movie) = {
movies.value.-=(movie)}
#dom def Want = {
println(movies, "!##!##!##!")
<div class="want">
<ul>
{for (movie <- movies.bind) yield {
<li>
<div>
<span>
{movie.title.bind}
</span>
<button onclick={event: Event => {
event.preventDefault()
remove(movie)
}}></button>
</div>
</li>
}}
</ul>
</div>
}
However, the code doesn't work.
Please change for (movie <- movies.value) to for (movie <- movies).
According to the Scaladoc of value method:
Note: This method must not be invoked inside a #dom method body.
I have NgbTypeahead component which uses a list of objects like
export class Example {
name: string;
value: number;
}
as source. It searches by name(value is used as placeholder in another input). I put it inside the form, set the formControlName:
<form [formGroup]="myForm" novalidate (ngSubmit)="save(myForm.value, myForm.valid)">
<input formControlName="name" name="exampleName" type="text" [ngbTypeahead]="search"
[resultFormatter]="formatMatches"
[inputFormatter]="formatMatches"
/>
<!--..some code-->
<br><button type="submit">Submit</button>
</form>
But when I submit it, the selected object of type Example is passed, but if instead I need the value of input, what should I do?
EDITED
Removed ngModel.
The code of formatMatches function:
formatMatches = (value: any) => value.name || '';
I am trying to build an input helper for Play Framework in Scala.
I would like to have my inputs of type radio and checkbox to be printed differently than the standard text or password input types ?
Here is my custom helper:
#(elements: helper.FieldElements)
<div class="form-group">
<label for="#elements.id" class="col-lg-2 control-label">#elements.label</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="#elements.id" />
</div>
</div>
But this prints an text input instead of checkbox input. Which is strange behaviour.
I've read the documentation, but couldn't find anything about it.
Here is how I import this helper to view:
#implicitFieldConstructor = #{ FieldConstructor(generic.views.html.FormHelpers.twitterBootstrapInputSupraClub.render) }
#checkboxFieldConstructor = #{ FieldConstructor(generic.views.html.FormHelpers.twitterBootstrapInputSupraClubCheckbox.render) }
And this is how I call helpers to build input (generates inputs) in view:
#inputText(
accountRegistrationForm("email"),
'_label -> "email"
)
#inputPassword(
accountRegistrationForm("password"),
'_label -> password
)
#inputRadioGroup(
accountRegistrationForm("regulationAcceptance"),
options = Seq("true"->"Yes"),
'_label -> "I agree with regulation",
'type -> "radio"
)(handler = checkboxFieldConstructor, implicitly[Lang])
I might be missing something here but as far as I can see, you seem to me missing the right input type.
In your helper, try changing <input type="text"... to <input type="radio"...
You can pass the input type dynamically, too. e.g.
#(elements: helper.FieldElements, inputType: String)
<div class="form-group">
<label for="#elements.id" class="col-lg-2 control-label">#elements.label</label>
<div class="col-lg-10">
<input type="#inputType" class="form-control" id="#elements.id" />
</div>
</div>
EDIT:
I have something similar to this for radio buttons:
given that my userDetailForm contains canLogOn:
"company" -> nonEmptyText,
"canLogon" -> boolean,
"canTrade" -> boolean,
I created a function in views: radioSet(fieldName: String)
#radioSet(fieldName: String) = {
<label for="#fieldName">Can Logon</label>
<input name=#fieldName id=#fieldName type="radio" value = "true"
#if(userDetailForm(fieldName).value.getOrElse("false").equals("true"))
{checked}>
}
Then I call it when I need it:
#radioSet("canLogon")
And I get: http://imgur.com/RG60wxV (sorry I cant post images yet)