my component livewire
public $images = [];
public function rules()
{
return [
'images.*.name' => 'required|max:255',
];
}
blade.php
<div id="images">
#foreach($images as $index => $image)
<div class="card" wire:key="image-field-{{$images[$index]['id']}}">
<img src="{{$images[$index]->original_url}}" class="card-img-top" alt="{{$images[$index]->name}}" />
<input type="text" name="item-{{$index}}-name" id="item.{{$index}}.name" wire:model="images.{{$index}}.name" />
<div class="card-footer">
<button wire:click="changeImageName({{$image['id']}},{{$images[$index]['name']}})">Update</button>
{{$images[$index]->name}}
</div>
</div>
#endforeach
</div>
so wire:model="images.{{$index}}.name" not working, not changing after typing
and update will error
Uncaught SyntaxError: identifier starts immediately after numeric literal
Make function update fix my problem
public function updated($name, $value)
{
foreach($this->images as $image){
$i = Image::find($image['id']);
$i->name = $image['name'];
$i->update();
}
}
Maybe try adding the multiple attribute in the input tag. and change the wire:model value to just have images
<input type="text" ... wire:model='images' multiple />
I Hope that helps
Related
disCoins.map((c) => {
let subTotal;
function calcSubTotal(subAmount){
subTotal = (Number(c.current_price) * Number(subAmount));
console.log(subAmount);
return subTotal;
}
return(
<div id="calcElement">
<img id="coinImg" src={c.image} alt="Coin img"></img>
<div id="calcInfo">
<div id="calcName">{c.name}<span id="calcSymbol"> ({capitalize(c.symbol)})</span></div>
<div id="calcPrice">
${formatNumber(c.current_price)}
<span id="calcChange" className={c.price_change_percentage_24h < 0 ? "loss" : "gain"}> ({c.price_change_percentage_24h}%)</span>
</div>
</div>
<div id="x">
<span>×</span>
</div>
<div id="amountInput">
<form>
<input id="amountInputField" type="number" placeholder="Amount of Crypto Owned" defaultValue='0' onChange={calcSubTotal(Number(3))}></input>
</form>
</div>
<div id="eq">
<span>=</span>
</div>
<div id="subTot">
<span id="subTotal">${formatNumber(subTotal)}</span>
</div>
</div>
)})
How would I be able to get the value of that input field and have it change when it updates? React doesn't let me use useState and DOM gives me an error when I add the first item into the list because it reads the value as null.
I want to show a list of movies and add a new movie by adding it to the array.
The html file:
<!-- FOREACH the movies -->
<div ng-controller="homeController" ng-repeat="movie in movies | orderBy : order">
<div class="movie-wrapper">
<h1>{{movie.name}}</h1>
<p>IMDB: IMDB</p>
</div>
</div>
<!-- ADD a new movie to the array -->
<div ng-controller="homeController">
<h3>Add new movie:</h3>
<form name="movieForm" ng-submit="addMovie(movieInfo)">
<div class="form-group new-movie">
<label for="Title">Title:</label>
<input type="text" class="form-control" name="title" ng-model="movieInfo.title">
</div>
<div class="form-group new-movie">
<label for="IMDB">IMDB:</label>
<input type="text" class="form-control" name="imdb" ng-model="movieInfo.imdb">
</div>
<button type="submit" class="btn btn-primary">Add movie</button>
</form>
</div>
The javascript file:
var app = angular.module('movie-app', ["ngRoute"]);
app.controller("homeController", function($scope) {
$scope.movies = getMovies();
// Method to add a new movie
$scope.addMovie = function(movieInfo) {
$scope.movies.push({
name : movieInfo.title,
imdb_url: movieInfo.imdb
});
console.log("Movie added");
}
});
function getMovies() {
return [{
name: 'Inception',
imdb_url: 'http://www.imdb.com/title/tt1375666/'
}];
}
After pressing the submit button, in the console I did not get any error message, but somehow the UI does not get's refreshed.
I think that somehow the controller does not get a reference/bind to the same array or dom element when I'm pushing the new entry.
First of all, i'm pretty sure you should have an error in your console
You make 3 mistakes :
1. You have an error in your getMovies() function (missing curly brackets {})
function getMovies() {
return [{
name: 'Inception',
imdb_url: 'http://www.imdb.com/title/tt1375666/'
}];
}
Why curly brackets are important ?
name and imdb_url are properties object. In JavaScript, an object must have curly brackets before and after. But your function getMovies returns and array of 1 element, so you have to surround your object with brackets []
2. You also have an error when you call console.log (missing quote ")
console.log("Movie added);
3. And the last one : you have to remove the parenthesis }) (the line after console.log)
The result :
angular.module('movieApp', [])
.controller("homeController", function($scope) {
$scope.movies = getMovies();
// Method to add a new movie
$scope.addMovie = function(movieInfo) {
$scope.movies.push({
name: movieInfo.title,
imdb_url: movieInfo.imdb
});
console.log("Movie added");
};
});
function getMovies() {
return [{
name: 'Inception',
imdb_url: 'http://www.imdb.com/title/tt1375666/'
}];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="movieApp" ng-controller="homeController">
<!-- FOREACH the movies -->
<div ng-repeat="movie in movies | orderBy : order">
<div class="movie-wrapper">
<h1>{{movie.name}}</h1>
<p>IMDB: IMDB
</p>
</div>
</div>
<!-- ADD a new movie to the array -->
<div>
<h3>Add new movie:</h3>
<form name="movieForm" ng-submit="addMovie(movieInfo)">
<div class="form-group new-movie">
<label for="Title">Title:</label>
<input type="text" class="form-control" name="title" ng-model="movieInfo.title">
</div>
<div class="form-group new-movie">
<label for="IMDB">IMDB:</label>
<input type="text" class="form-control" name="imdb" ng-model="movieInfo.imdb">
</div>
<button type="submit" class="btn btn-primary">Add movie</button>
</form>
</div>
</div>
I am trying to migrate my demo project to Angular as I am learning the same. But I faced a dilemma as whether to opt for a razor view form validation while adding or rather updating some info on the client side
or to opt for Angular JS ?
So In Angular How would I achieve the same.
Suppose I have a _AddDetails.cshtml partial view :
#model MvcApplication4.Models.Student
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend><strong>Create a record</strong></legend>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DepartmentID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DepartmentID)
#Html.ValidationMessageFor(model => model.DepartmentID)
</div>
<p>
<input type="submit" class="createDetails" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
and in MVC I have opted for FluentValidation of the model.
The model looks like :
[FluentValidation.Attributes.Validator(typeof(StudentViewModelValidator))]
public class Student
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int StudentId { get; set; }
public String LastName { get; set; }
public String FirstName { get; set; }
public String UserName { get; set; }
public String Password { get; set; }
[ForeignKey("Department")]
public int DepartmentID { get; set; }
//Department Navigational Property
public Department Department { get; set; }
}
And the validation looks like :
public class StudentViewModelValidator : AbstractValidator<Student>
{
public StudentViewModelValidator()
{
RuleFor(m => m.FirstName)
.NotEmpty().WithMessage("First Name is required.")
.Matches(#"^\D*$").WithMessage("Numbers are not allowed in First Name");
RuleFor(m => m.LastName)
.NotEmpty().WithMessage("Last Name is required.")
.Matches(#"^\D*$").WithMessage("Numbers are not allowed in Last Name");
RuleFor(m => m.UserName)
.NotEmpty().WithMessage("User Name is required.")
.Matches(#"^[a-zA-Z0-9\.\$]*$").WithMessage("Only . and $ are allowed special characters in a user name");
RuleFor(m => m.Password)
.NotEmpty().WithMessage("Password is required.")
.Length(4, 10).WithMessage("Password should be 4 to 10 characters long")
.Matches(#"^(?=(\D*\d){2,})(?=([^a-zA-Z]*[a-zA-Z]))(?=[^\.\$\~\&]*[\.\$\~\&]).*").WithMessage("Password should contain at least 2 digits,a letter and at least a special character in it");
}
But in angular if I re-build my view instead of this razor template how would I achieve these sort of complex regex validations ?
I know I have something like
ng-required
ng-minlength
ng-maxlength
But how would I achieve like the above razor validations?
Use can use ng-pattern for regex
<script>
angular.module('ngPatternExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.regex = '\\d+';
}]);
</script>
<div ng-controller="ExampleController">
<form name="form">
<label for="regex">Set a pattern (regex string): </label>
<input type="text" ng-model="regex" id="regex" />
<br>
<label for="input">This input is restricted by the current pattern: </label>
<input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
<hr>
input valid? = <code>{{form.input.$valid}}</code><br>
model = <code>{{model}}</code>
</form>
</div>
Reference :
https://docs.angularjs.org/api/ng/directive/ngPattern
I implemented the validation in my MVC project that uses angular, so I used the ng-pattern, I had a problem trying to include some special chars as valid for the user name: "#", "_" and "-".
The only way I succeed was to add them as separate repeatable chars at the end of my pattern:
ng-pattern="/^[a-zA-Z0-9.]*[#('_')]*[#('-')]*[#('#')]*$/"
I hope this works for you.
So I have the following div:
<div id="chatrooms" ng-controller="TableMsgController">
<section id="chatroom">
<div id="messages" >
<ul>
<li ng-repeat="entry in seenMsgs">{{entry.msg}}</li>
</ul>
</div>
<form action="">
<input type="text" id="userMsg" ng-model="userMsg">
<input type="button" class="gButton" id= "sendMsgBtn" value="Send" ng-click="sendMsg()" />
</form>
</section>
</div>
And I have the following controller:
tables.controller('TableMsgController',function ($rootScope,$scope) {
$scope.msgSeen = [];
$scope.sendMsg = function () {
//console.log("sendMsg button pushed");
//console.log($scope.userMsg);
$scope.msgSeen.push( {'msg':$scope.userMsg} );
// console.log($scope.msgSeen);
};
The ng-repeat is not working.
Any idea why?
Z
Two things I can spot:
a) You're missing a closing brace on sendMsg:
tables.controller('TableMsgController',function ($rootScope,$scope) {
$scope.msgSeen = [];
$scope.sendMsg = function () {
//console.log("sendMsg button pushed");
//console.log($scope.userMsg);
$scope.msgSeen.push( {'msg':$scope.userMsg} );
// console.log($scope.msgSeen);
} <---------------------------------------------- :)
};
and b) you define msgSeen in the scope but are attempting to iterate over seenMsgs:
<li ng-repeat="entry in seenMsgs">{{entry.msg}}</li>
Resolve both of these and see if that fixes it.
I am working on Single Page Application and using Angular-TypeAhead when i write something in textbox it shows me suggestions but when i select the suggestion then the values of Textbox become Object object instead of name
here is my HTML Markup
<div class="bs-example" style="padding-bottom: 24px;" append-source>
<form class="form-inline" role="form">
<div class="form-group">
<label><i class="fa fa-globe"></i> State</label>
<input type="text" class="form-control" ng-model="selectedState" ng-options="state.FirstName for state in states" placeholder="Enter state" bs-typeahead>
</div>
</form>
</div>
and here is my AngularJS code
var app = angular.module('mgcrea.ngStrapDocs', ['ngAnimate', 'ngSanitize', 'mgcrea.ngStrap'])
.controller('TypeaheadDemoCtrl', function ($scope, $templateCache, $http) {
$scope.selectedState = '';
$http.get('/api/servicesapi/GetAllClients')
.then(
function (result) {
//success
$scope.states = result.data;
},
function () {
//error
});
});
see the images here
Change ng-options="state.FirstName for state in states" to ng-options="state as state.FirstName for state in states"
This is the solution in Angular 4 and not angularJS
I added [inputFormatter]="formatMatches" to format the input (ngmodel) and [resultFormatter]="formatMatches" to format the data displayed
<input id="typeahead-format" type="text" [(ngModel)]="clickedItem"
name="profile" (selectItem)="selectedItem($event)"
[resultFormatter]="formatter" [inputFormatter]="formatter"
[ngbTypeahead]="search" #instance="ngbTypeahead"/>
and the formatter function is like this:
formatter = (x: { label: string }) => x.label;
x: is the object
For anyone using angular bootstrap and finding the same issue, I spent too long on this.
Essentially you need to consider the model to be a string on the way out and then converted to a string from the complex model returned from the api call.
You then need to hook into the OnSelect method to extract the complex object and store this (or the unique id form the object) in a separate variable. It is right then in the documents, but it is not given much prominence given that you would normally want a key / value pair from a typeahead. Not just a string.
https://valor-software.com/ngx-bootstrap/#/typeahead#on-select
Here is a code snippet from a typeahead which works fine, to set the search as the [name] value from a complex object and the selectedObject to be the whole item.
<pre class="card card-block card-header">Search: {{ search | json }}</pre>
<pre class="card card-block card-header">Selected: {{ selectedOption | json }}</pre>
<ng-template #customItemTemplate let-model="item" let-index="index">
<div>
<p>This is: {{ model.name }} Number: {{ model.id }} Index: {{ index }}</p>
<p>Some secondary information about {{ model.name }}</p>
</div>
</ng-template>
<input [(ngModel)]="search"
[typeahead]="suggestions$"
typeaheadOptionField="name"
(typeaheadOnSelect)="onSelect($event)"
[typeaheadAsync]="true"
typeaheadWaitMs="500"
[typeaheadMinLength]="3"
[typeaheadItemTemplate]="customItemTemplate"
class="form-control"
placeholder="Enter a street name">
<div class="alert alert-danger" role="alert" *ngIf="errorMessage">
{{ errorMessage }}
</div>
then in my component I have
ngOnInit(): void {
this.suggestions$ = new Observable((observer: Observer<string>) => {
observer.next(this.search);
}).pipe(
switchMap((query: string) => {
if (query) {
return this.YOURSERVICE.YOURMETHOD(query);
}
return of([]);
})
);
}
onSelect(event: TypeaheadMatch): void {
this.selectedOption = event.item;
}
your method should return an interface with a [name] property
This should be enough to get going. This is very old, but I passed through here before finding what I needed.