Model Abstracted Aurelia Validation

I recently completed an online course on Aurelia by Scott Allen where he introduced the Aurelia-Validation plugin for form validation.

As a result, my view-model now looks like this in edit.js:

import {inject} from "aurelia-framework";
import {MovieService} from "./movieService";
import {Router} from "aurelia-router";
import {Validation} from "aurelia-validation";

@inject(MovieService, Router, Validation)
export class Edit {

    constructor(movieService, router, validation) {
        this.service = movieService;
        this.router = router;
        this.validation = validation.on(this)
        .ensure("movie.title").isNotEmpty().hasLengthBetween(3, 50)
        .ensure("movie.releaseYear").isNotEmpty().isNumber().isBetween(1900, 2100)
        .ensure("movie.starRating").isNotEmpty().isNumber().isBetween(0, 5);
    }

    activate(params) {
        this.service.getById(params.id)
            .then(movie => {
                this.movie = movie;
           });
    }

    save() {
        this.validation.validate()
            .then(() => {
                this.service.save(this.movie)
                    .then(movie => {
                        let url = this.router.generate("home");
                        this.router.navigate(url);
                    });
            })
            .catch(() => {
            });
    }

}

I have also created a corresponding view in edit.html


<form class="form-horizontal"
    validate.bind="validation"
    submit.trigger="save()">

    <div class="form-group">
        <label class="col-sm-2" for="title">Title</label>
        <div class="col-sm-10">
            <input type="text" id="title" placeholder="Title" value.bind="movie.title" class="form-control"/>
        </div>
    </div>

    <!-- More form fields here -->

    <div class="pull-right">
        <a route-href="route:home" class="btn btn-default" role="button">Cancel</a>
        <input type="submit" class="btn btn-primary" value="Save" />
    </div>

</form>

The validation system is working flawlessly, preventing invalid data submissions as expected.

My next step involves moving the validation rules out of the view model and into a separate model class. I have created a new model called movieModel.js:

import {inject} from "aurelia-framework";
import {Validation} from 'aurelia-validation';
import {ensure} from 'aurelia-validation';

@inject(Validation)
export class MovieModel {

    @ensure(function(it){ it.isNotEmpty().hasLengthBetween(3, 50) })
    title = "";

    @ensure(function(it){ it.isNotEmpty().isNumber().isBetween(1900, 2100) })
    releaseYear = "";

    @ensure(function(it){ it.isNotEmpty().isNumber().isBetween(0, 5) })
    starRating = "";

    constructor(validation) {
        this.title = "";
        this.releaseYear = "";
        this.starRating = "";
    }
}

I then integrated the movieModel into the view model like so:

import {inject} from "aurelia-framework";
import {MovieService} from "./movieService";
import {Router} from "aurelia-router";
import {Validation} from "aurelia-validation";
import {MovieModel} from "./movieModel";

@inject(MovieService, Router, Validation, MovieModel)
export class Edit {

    constructor(movieService, router, validation, movieModel) {
        this.service = movieService;
        this.router = router;
        this.movie = movieModel;
        this.validation = validation.on(this.movie);
    }

    activate(params) {
        this.service.getById(params.id)
            .then(movie => {
                this.movie = movie;
           });
    }

    save() {
        this.validation.validate()
            .then(() => {
                this.service.save(this.movie)
                    .then(movie => {
                        let url = this.router.generate("home");
                        this.router.navigate(url);
                    });
            })
            .catch(() => {
            });
    }

}

To implement these changes in the view edit.html, I had to add the validate attribute to the input fields like so:

<input type="text" id="title" placeholder="Title" value.bind="movie.title" class="form-control"/>

changed to:

<input type="text" id="title" placeholder="Title" value.bind="movie.title" validate="title" class="form-control"/>

However, after editing a movie retrieved from the service and attempting to save it, all properties are flagged as "required" by the validation system.

I suspect that the line this.validation = validation.on(this.movie) in the view model's constructor is linking the validation to an empty instance of the model. Unfortunately, I'm unsure of how to resolve this issue.

Answer №1

It is important to implement validation whenever there are changes made to your model.

activate(params) {
    this.service.getById(params.id)
        .then(movie => {
            this.movie = movie;
            this.validation = this.Validation.on(this.movie);
       });
}

Additionally, make sure to include it in the constructor as well.

this.Validation = validation;

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Troubleshoot: jQuery Datalink functionality not functioning properly with object methods

Within my JavaScript code, I have defined an object that includes various properties and an instance method that calculates a value based on two of those properties. To synchronize the object's property values with form elements in the UI, I am utili ...

Encountering an undefined value from state when implementing useEffect and useState

One issue I am facing is that the state of my projects sometimes returns as undefined. It's puzzling to me why this happens. In the useEffect hook, I have a function that fetches project data from an API call to the backend server. This should return ...

Error: Attempting to access 'title' property of undefined object leads to Uncaught TypeError

I am attempting to extract content from a Google Blogger Feed that can be found at this link. I am using JavaScript code from here. When inspecting the elements, I encountered a specific red warning message: Uncaught TypeError: Cannot read property ' ...

Updating a global variable in Angular after making an HTTP call

I'm facing a challenge where I have a global variable that needs to be updated after an HTTP GET call. Once updated, I then need to pass this updated variable to another function. I'm struggling to figure out the best approach for achieving this. ...

Using Javascript to dynamically add SVGs from an array

Having issues with displaying SVG images in a quiz I'm building. I have a folder full of SVGs that correspond to each multiple choice option, but I can't seem to get the pathway right for them to show up properly. I've tried using template l ...

Using AngularJS to hide elements within a nested dictionary structure

My dictionary structure is as follows: var data = { a: [1, 2, 3, 4, 5], b: [ [1, 2], [3, 4], [5, 6] ] }; Currently, I am using ng-hide to hide an element if the value 2 exists in data->a. Here's how it's implemented: <i ...

The data from the Vue.js instance is not available when accessing the Vuex store

My current task involves utilizing an API call to a django-rest backend in order to populate my data-store. The API call is functioning properly. Upon loading index.html, I am able to inspect both store_.state.products and v.$store.state.products, which s ...

Combining TypeScript and JavaScript for efficient mixins

I came across an article on MDN discussing the usage and creation of mix-ins (link). Intrigued, I decided to try implementing it in TypeScript: type Constructor = new (...args: any) => any; function nameMixin(Base: Constructor) { return class extends ...

What is the reason my answer for the powerset problem is flawed? Both my recursive and iterative methods are attached for review

How can I generate all possible subsets from an array of unique integers? For instance, if I have powerSet[1,2,3], the expected output should be [[], [1], [2], [3], [1,2], [1,3], [2,3], [1,2,3]] I've tried a recursive approach: function powerset(arr ...

Instructions on how to eliminate the minutes button from Material UI datetime picker

I'm currently working on customizing a datetimepicker from materialUI in ReactJS. My goal is to prevent the user from seeing or selecting minutes in the picker interface. Despite setting the views prop to include only year, month, date, and hours, use ...

Changing the disabled textfield colour in Material-UI

I am looking to enhance the visibility of disabled text in a textfield by making it darker than the current light color: https://i.sstatic.net/Iw6Dp.png I have attempted to achieve this using the following code snippet: import { withStyles } from ' ...

Automatically fill in the Modal popup

Today, I encountered a challenge while trying to keep the current page in a jQuery data table. Clicking on the "Edit" link in a row would open a modal pop-up and fill in the controls. However, this action resulted in a postback that set the page back to pa ...

Utilizing PHP Variables in an External JavaScript: A Step-by-Step Guide

I am attempting to utilize an array generated in PHP within my external JavaScript. My PHP code retrieves images from a directory based on the user ID provided via URL and stores them in an array. I aim to use this array in JavaScript to create a photo sli ...

Pulling down the data with Ajax "GET"

When a user clicks on a button, a zip file will be downloaded. I have the necessary components in place, but I am struggling to ensure they work together seamlessly. The "GET" call will retrieve byte content with the content type specified as application/ ...

Angular JS is patient when waiting for asynchronous requests to complete

Once upon a time in a factory httpFactory.factory('setFavorability', function($http){ return{ Like: function(id){ return $http.get('http://localhost:51265/Film/Like/' + id); } } ...

I am trying to update the content in ckeditor when a different option is selected, but for some reason it is not working

jquery issue: the jquery that I added and the content doesn't change even though the "alert(model);" works fine <script> $(document).ready(function() { $("select.modele").change(function() { var modele = $(this) ...

Is there a way to determine if a click occurred outside of a div without relying on stopPropagation and target event?

My goal is to track multiple div elements and determine if a click occurs outside of any of these divs. I am looking for a solution that does not involve using stopPropagation or event.target as they have negative effects. Is there an alternative method to ...

Get Code Now Button

I operate a website dedicated to Amazon reviews, and I am in need of a button that can request a code from a text file uploaded by the seller. My question is how can this be achieved using HTML? I have been experimenting with this sample: <!-- Butt ...

Implementing React selectors to manage the state changes on page load and when a user

I'm currently delving into React selectors with ReSelect, and while things seem to be going well, I have a feeling that there may be an issue in my logic. 1 - Upon receiving an AJAX response, I obtain a list of "categories" consisting of id, name, an ...

Error encountered in Angular after consolidating JavaScript files into a single file: [$injector:modulerr]

After developing an Angular application, everything seemed to be functioning well when I included the controllers.js, routes.js, directives.js files separately in index.html. However, upon attempting to combine these files into a single js file using gul ...