Binding View-Models with collection properties - aurelia

My view model has a sole property, currentProject, which itself has a child property that is an array of strings. When I bind everything to the view, all the data populates correctly including the array of strings. When I edit the data, the array of strings is not updated.
Is there something specific I have to do here to make this a two-way binding? I tried the the two-way command but it made no difference.
My View Model looks like this:
export class Edit {
currentProject;
...
}
CurrentProject gets set to an instance of the project class:
export class Project {
id = '';
name = '';
modifiedDate = '';
createdBy = '';
students = [];
}
My edit view looks like this:
<template>
<section>
<h1>Edit ${currentProject.name}</h1>
<form role="form" submit.delegate="save()">
<label for="name">Project Name</label>
<input type="text" maxlenth="100" id="name" value.bind="currentProject.name" />
<h2>Students</h2>
<div repeat.for="student of currentProject.students">
<label for="name${index}">Student ${$index + 1}</label>
<input type="text" maxlenth="100" id="name${$index}" value.bind="student" />
</div>
<button class="btn">Add Student</button>
<button type="submit" class="btn btn-primary">Update project</button>
</form>
</section>
</template>
Any help would be greatly appreciated. I suspect I am missing some minor detail.
Thanks,
Andrew

Looks like the issue here is due to strings (primitive type) immutability, there is no reference between string you are editing in input field and the one in the array, it's just two different copies.
That being said, there are two approaches you can take to make it work properly. The best one is to have array of object for students, maybe like this:
[{name: 'Tomas Mann'}, {name: 'Alex Bloom'}]
then repeat.for part would look like:
<div repeat.for="student of currentProject.students">
<label for="name${index}">Student ${$index + 1}</label>
<input type="text" maxlenth="100" id="name${$index}" value.bind="student.name" />
</div>
This data structure is also more flexible. For example, you can add additional student information like age, score, etc. You could even have students array to be an array of Student objects students: Student[], etc.
If you still want to use array of simple strings then you could do this:
<div repeat.for="student of currentProject.students">
<label for="name${index}">Student ${$index + 1}</label>
<input type="text" maxlenth="100" id="name${$index}" value.bind="$parent.currentProject.students[$index]" />
</div>

Related

Using ref in a repetitive environment

I'm using a custom element to print the length of an input element. I got it working in a regular environment, but I have trouble creating unique refs in a repeat.for environment
I've tried using combinations of ref=name$index or ref=name${$index}, but none of them work so far.
In a non-repetitive environment, this works
<div class="row">
<label>
Name
<my-custom-element field.bind="name"></my-custom-element>
<input
type="text"
name="name"
ref="name"
value.bind="name"
maxlength="150" />
</label>
</div>
However, once I use repeat for, it stops working, cause I am using field.bind and ref wrongly. E.g.
<div repeat.for="item of items" class="row">
<label>
Name
<my-custom-element field.bind="name${$index}"></my-custom-element>
<input
type="text"
name="name${$index}"
ref="name${$index}"
value.bind="item.name"
maxlength="150" />
</label>
</div>
I'm just trying to make the ref look something like name0, name1, name2 etc, so that it is unique.
The error looks like Parser Error: Unconsumed token { at column 5 in expression [name${$index}]
You are iterating through items, which presumably is an array of objects having a name property. I think you want something more like the following:
<div repeat.for="item of items" class="row">
<label>
Name
<my-custom-element field.bind="item.name"></my-custom-element>
<input
type="text"
name="item.name"
ref="item.name"
value.bind="item.name"
maxlength="150" />
</label>

.NET Core Razor Pages Data Binding with partial views on form submission

I've got a an object with an Address object as a property which is used several places in my application. I made a partial view which looks like
#model Address
<div>
<div class="form-group">
<label asp-for="#Model.AddressLine1"></label>
<input asp-for="#Model.AddressLine1" />
</div>
....
I use the form like
<form method="post">
<div class="form-group">
<input asp-for="#Model.Request.Business.Owners[0].FirstName" />
<input asp-for="#Model.Request.Business.Owners[0].LastName" />
</div>
<input type="submit"/>
</form>
the data renders fine on the entire form, including the partial Address view. when I submit the form, everyone I reference the Address partial I get back as null when I submit the form, while the other data is data bound correctly. Is it possible to bind data to a partial view and have it submit with a form post correctly?
Likely, you're not providing context to the partial, so that it can generate the names properly. As-is, the partial is going to want to generate names like AddressLine1, when what you actually need for proper binding is Request.Business.Owners[0].Address.AddressLine1. I'm assuming you're doing something like:
<partial name="_Address" model="Request.Business.Owners[0].Address" />
Instead, you need to use the for attribute:
<partial name="_Address" for="Request.Business.Owners[0].Address" />

how to get a reference to the specific v-model in form

I'm new to Vue2 and am trying to to get a reference to a model's value in a form to be passed to a method. I have:
<div v-for="n in maxLength">
<input v-model='price.matrix_prices[n]' /><div #click="fillPrices(?)">set all to this price</div>
{{n}}</div>
The matrix_prices is a hash with specified values. Lets say someone fills in 8 in the input model, how would I get a reference so that ? would be eight?
Do you have access to n in the function as below?
<div v-for="n in maxLength">
<input v-model='price.matrix_prices[n]' />
<div #click="fillPrices(n)">set all to this price
</div>
{{n}}
</div>
If yes write the function like this:
methods: {
fillPrices(n) {
var data = this.price.matrix_prices[n];
//do something with the data
}
}

Aurelia repeater: model.bind is not working for radio buttons

I am creating a set of radio buttons in Aurelia with the code like this:
<div repeat.for="option of options">
<input type="radio" id="${option}_id" name="radio_options" model.bind="option" checked.bind="optionValue"/>
<label for="${option}_id" id="${option}_label">${option}</label>
</div>
However, doing it this way I discovered that model.bind is not working - the optionValue in corresponding class is not populated when radio button is checked. Similarly when some value is assigned to optionValue in the class, the appropriate radio button is not checked. I found this happening only with repeater. Options are numbers in my case. Could you please help me to find out what may be wrong here?
The first problem is that model.bind should be used when working with objects. Since you're working with a primitive type, you should use value.bind instead.
The second problem is that input values are always strings, so when setting an initial value, it must be a string. For example:
Html:
<template>
<div repeat.for="option of options">
<input type="radio" id="${option}_id" name="radio_options" value.bind="option" checked.bind="optionValue"/>
<label for="${option}_id" id="${option}_label">${option}</label>
</div>
<p>Selected Option: ${optionValue} </p>
</template>
JS:
export class App {
options = [ 1, 2, 3, 4 ]
optionValue = '3';
}
If you really want to use int in your view-model, you can create a ValueConverter to convert the value to int when passing it to/from the view. For instance:
export class AsIntValueConverter {
fromView(value) {
return Number.parseInt(value);
}
toView(value) {
return value.toString();
}
}
Usage:
<input type="radio" id="${option}_id" name="radio_options" value.bind="option" checked.bind="optionValue | asInt"/>
Running Example https://gist.run/?id=1465151dd5d1afdb7fc7556e17baec35

Textbox and variables javascript and HTML

I want to set two JavaScript variables as the values of these textboxes.
Can anyone can help me?
<form name="myform1">
<input type="number" name="pop_size" value="3">
<input type="button" value="Pop Size" id="population" onclick="setValue()">
</form>
<form name="myform2">
<input type="number" name="totalIterations" value="2">
<input type="button" value="Iterations" id="Iterations" onclick="setValue()">
</form>
You can use getElementsByName() to get a list of elements by their names in the form. Since your names are unique (which isn't necessary in the spec, but is a good idea for this exact reason), the array returned by that function should have exactly one element in it. Something like this:
var firstVariable = document.getElementsByName('pop_size')[0].value;
var secondVariable = document.getElementsByName('totalIterations')[0].value;
Or did you mean that you want to set the values to what's in a variable? That would be the reverse:
document.getElementsByName('pop_size')[0].value = firstVariable;
document.getElementsByName('totalIterations')[0].value = secondVariable;