Angular Filter Dot Notation - angularjs

There are a lot of questions similar to this where the thing being filtered in an ng-repeat is a property of an object, but my question is different. My filter itself is applying to an array collection of objects with nested properties, and the dot notation isn't working.
Like so:
<div class="col-sm-4"><div id="searchContainer" style="position:relative;text-align:center;">
<label for="search-input"><i class="fa fa-search"></i></label>
<input id="search-input" ng-model="userInputSearch" placeholder="Student Name" autocorrect="off" tabindex="1">
</div></div>
<div class="col-sm-4"><div id="searchContainer" style="position:relative;text-align:center;">
<label for="search-input"><i class="fa fa-search"></i></label>
<input id="search-input" ng-model="audioInputSearch" placeholder="Audio Name" autocorrect="off" tabindex="1">
</div></div>
<!-- Search Bars Above, Ng-Repeat Below -->
<div class="col-sm-4" ng-repeat="a in audio | filter:{ uploader: userInputSearch } | filter: {audio.name: audioInputSearch} track by $index ">
<div class="tile nobig #{{colors[$index]}}">
#{{a.audio.name}}</br>
Uploaded By <a class="white" target="_self" href="http://example.com/user/#{{a.audio.user_id}}">#{{a.uploader}}</a>
</br>
Length: #{{a.audio.Length|HHMMSS}}</br>
<i class="fa ear fa-play"></i>
</br></br>
</div>
</div>
The array of objects I am repeating over:
[{"audio":{"id":"43","user_id":"74","name":"controlla","url":"controlla.wav","Length":"234","LengthD":"short","ForTask":"True","created_at":"2016-06-21 13:06:06","updated_at":"2016-06-21 13:06:06"},"uploader":"Summer"},{"audio":{"id":"52","user_id":"74","name":"roywoodshowifeel","url":"roywoodshowifeel-56e65.wav","Length":"225","LengthD":"short","ForTask":"True","created_at":"2016-06-21 22:11:15","updated_at":"2016-06-21 22:11:15"},"uploader":"Summer"},{"audio":{"id":"53","user_id":"74","name":"bodman","url":"bodman-fc378.wav","Length":"194","LengthD":"short","ForTask":"True","created_at":"2016-06-22 00:05:41","updated_at":"2016-06-22 00:05:41"},"uploader":"Summer"},{"audio":{"id":"54","user_id":"74","name":"shake070sundaynight","url":"shake070sundaynight-6119e.wav","Length":"274","LengthD":"short","ForTask":"True","created_at":"2016-06-22 00:09:05","updated_at":"2016-06-22 00:09:05"},"uploader":"Summer"},{"audio":{"id":"55","user_id":"74","name":"audio1","url":"audio1-f895c.wav","Length":"121","LengthD":"short","ForTask":"True","created_at":"2016-06-22 01:45:39","updated_at":"2016-06-22 01:45:39"},"uploader":"Summer"},{"audio":{"id":"56","user_id":"74","name":"audio2","url":"audio2.wav","Length":"726","LengthD":"short","ForTask":"True","created_at":"2016-06-22 01:46:05","updated_at":"2016-06-22 01:46:05"},"uploader":"Summer"},{"audio":{"id":"59","user_id":"74","name":"loner","url":"loner-2070b.wav","Length":"209","LengthD":"short","ForTask":"True","created_at":"2016-06-22 01:57:51","updated_at":"2016-06-22 01:57:51"},"uploader":"Summer"},{"audio":{"id":"60","user_id":"74","name":"comeandseeme","url":"comeandseeme-41399.wav","Length":"232","LengthD":"short","ForTask":"True","created_at":"2016-06-22 01:58:28","updated_at":"2016-06-22 01:58:28"},"uploader":"Summer"},{"audio":{"id":"61","user_id":"74","name":"loner","url":"loner-1d416.wav","Length":"209","LengthD":"short","ForTask":"True","created_at":"2016-06-22 01:58:30","updated_at":"2016-06-22 01:58:30"},"uploader":"Summer"},{"audio":{"id":"63","user_id":"74","name":"comeandseeme","url":"comeandseeme-d41e7.wav","Length":"232","LengthD":"short","ForTask":"True","created_at":"2016-06-22 02:03:02","updated_at":"2016-06-22 02:03:02"},"uploader":"Summer"},{"audio":{"id":"64","user_id":"74","name":"nopolice","url":"nopolice-0b883.wav","Length":"258","LengthD":"short","ForTask":"True","created_at":"2016-06-22 02:12:57","updated_at":"2016-06-22 02:12:57"},"uploader":"Summer"},{"audio":{"id":"65","user_id":"74","name":"ovo","url":"ovo.wav","Length":"4080","LengthD":"long","ForTask":"True","created_at":"-0001-11-30 00:00:00","updated_at":"-0001-11-30 00:00:00"},"uploader":"Summer"}]
So how do I get it to filter by audio.name without throwing an unexpected . error?

Related

AngularJs: Input value changes in display too using ng-model. I have tried ng-value and ng-bind too

<div class="form-group">
Name <input type="text" class="form-control" placeholder="item" ng-model="shoppingItem.itemName" required>
</div>
<div class="form-group">
Image URL <input type="url" class="form-control" placeholder="item" ng-model="shoppingItem.imgUrl" required>
</div>
<div class="form-group">
<button type="button" class="btn btn-success" ng-click="save()" >Success</button>
</div>
app.controller('recipebookController',function($scope,$routeParams,RecipeService,$location){
$scope.shoppingItems =RecipeService.shoppingItems;
$scope.rp="Route parameter value"+RecipeService.shoppingItems[0].itemName;
$scope.save = function(){
RecipeService.save($scope.shoppingItem);
$location.path("/");
}
});
<div class="col-xs-12">
<ul class="list-group">
<li ng-repeat="item in shoppingItems"class="list-group-item text-center clearfix">
<span style="font-weight:bold">{{item.itemName}}</span>
<img ng-src="{{ item.imgUrl }}" width="40" height="40"/>`
</li>
</ul>
</div>
When I enter save, the new data is saving row wise perfectly and displaying but when I re-enter new value into the input. The previously save value get changes as I type.
The issue that you're facing is that when you call RecipeService.save($scope.shoppingItem);, the RecipeService is saving the reference to your scope variable.
So, instead of assigning the variable directly, I might try doing something like this:
RecipeService.save(angular.copy($scope.shoppingItem));
This will create a new copy of the object referenced by $scope.shoppingItem and will allow you to edit one of those objects without affecting the other.

$index in ng-class for form validation

I want to validate an angular form input and give it a class if is not $valid, the problem is, it´s inside a ng-repeat looping an array of int, and the input name is based on the $index:
<li ng-repeat="item in selectedItem.data.ax_ch">
<div ng-class="{'has-error':!form.ax_$index.$valid}">
<input type="text" id="ax_{{$index}}" name="ax_{{$index}}" ng-model="item" required=""/>
</div>
</li>
Everything gets the $index in the output, but the ng-class:
<li ng-repeat="item in selectedItem.data.ax_ch">
<div ng-class="{'has-error':!form.ax_$index.$valid}">
<input type="text" id="ax_0" name="ax_0" ng-model="item" required=""/>
</div>
</li>
What I expected it to be:
<li ng-repeat="item in selectedItem.data.ax_ch">
<div ng-class="{'has-error':!form.ax_0.$valid}">
<input type="text" id="ax_0" name="ax_0" ng-model="item" required=""/>
</div>
</li>
I have searched and people have similar problems but none of them have been solved so far. Is there any angular-super-hero-master-plus-advanced who can help me with it :) ?
Because you are constructing the property/key on form dynamically, you do the same thing you would in normal Javascript: use square["bracket"] notation.
Change your markup to:
<li ng-repeat="item in selectedItem.data.ax_ch">
<div ng-class="{'has-error':!form['ax_' + $index].$valid}">
<input type="text" id="ax_{{$index}}" name="ax_{{$index}}" ng-model="item" required=""/>
</div>
</li>

angular ng-repeat creating multiple forms syntax error

I'm ng-repeating over a collection of items, and each item I want to have its own form and its own submit button, which will send that form info to the submit function. I needed to know which item is being submitted, so I figured I'd create one form per item and that would indicate which one is being submitted. Currently, it's in an li ng-repeat like so:
<input ng-model="query" type="text" placeholder="Filter by" autofocus>
<ul class="gNow">
<li ng-repeat="item in selRole.selectRoles | multifilter:query">
<form name="selRoleForm-{{item.rowId}}" ng-submit="selRole.selectRole(selRoleForm-{{item.rowId}})" novalidate>
<div class="card">
<p>Card Name: {{item.cardName}}</p>
<p>.. other form elements here ..</p>
<p><button type="submit">Select</button></p>
</div>
</form>
</li>
</ul>
I'm getting the following error:
[$parse:syntax] Syntax Error: Token '{' invalid key at column 33 of
the expression [selRole.selectRole(selRoleForm-{{item.rowId}})]
starting at [{item.rowId}})].
What am I doing incorrectly - or is there a better way to approach this problem?
This SO post is the closest that I could find to my problem, but still, I'm not sure I understand how to adjust to my specific needs.
UPDATE:
Thanks to all the responses which lead me to the solution. I needed to not include the form name in the submit function, but the item instead. That was all that was missing.
old (syntax error):
ng-submit="selRole.selectRole(selRoleForm-{{item.rowId}})"
new (working):
ng-submit="selRole.selectRole(item)"
Just store the form name in your ng-repeated array:
<input ng-model="query" type="text" placeholder="Filter by" autofocus>
<ul class="gNow">
<li ng-repeat="item in selRole.selectRoles | multifilter:query">
<form name="{{item.formName}}" ng-submit="selRole.selectRole(item.formName)" novalidate>
...
Use ngForm :
<div class="form-group" ng-repeat="item in selRole.selectRoles | multifilter:query">
<ng-form name="userFieldForm">
<label></label>
<input >
</ng-form>
</div>
You just need to reverse the conversion in the concatenation of the names.
When parsing a parameter on ng-submit what you need to convert is the hard-coded string, not the rowId.
would be something like that:
<input ng-model="query" type="text" placeholder="Filter by" autofocus>
<ul class="gNow">
<li ng-repeat="item in selRole.selectRoles | multifilter:query">
<form name="selRoleForm-{{item.rowId}}" ng-submit="selRole.selectRole('selRoleForm-'+item.rowId)" novalidate>
<div class="card">
<p>Card Name: {{item.cardName}}</p>
<p>.. other form elements here ..</p>
<p><button type="submit">Select</button></p>
</div>
</form>
</li>

ng-repeat execution forces input to lose focus

I have an input that is created using ng-repeat
<div data-ng-repeat="(index, answer) in currentQuestion['possible_answers']" class="form-group">
<label class="col-md-3 control-label">Answer {{ index + 1 }}</label>
<div class="col-md-8">
<div class="input-icon">
<i class="fa fa-sun-o"></i>
<input data-ng-model="currentQuestion['possible_answers'][index]" type="text" class="form-control" >
</div>
</div>
</div>
I want this to prepopulate the inputs with the values that are in currentQuestion['possible_answers'] and I also want any changes to bind to this variable as well.
However, everytime I start typing into one of these text fields, I type one letter and then it looses focus of the input box. I have a feeling that this is because I start typing and the data bidning updates currentQuestion. Because currentQuestion is updated, the ng-repeat is executed again.
Is there a way to make the ng-repeat action a one off action isntead of constantly revalutating?
Yes (looking at the symptoms, you did not show us the data) your issue could be because your model is the text in the array that you (may have), so whenever you update the model, it will trigger digest cycle since ng-repeat is tracked by the text. You can easily fix this by providing. track by $index, so that the ng-repeat is watched over and repeat watch gets updated only when the array changes in its length.
<div data-ng-repeat="answer in currentQuestion['possible_answers'] track by $index" class="form-group">
<label class="col-md-3 control-label">Answer {{ $index + 1 }}</label>
<div class="col-md-8">
<div class="input-icon">
<i class="fa fa-sun-o"></i>
<input data-ng-model="currentQuestion['possible_answers'][$index]" type="text" class="form-control" >
</div>
</div>
</div>
Demo
You can also use $index to get the array's index. you do not need to iterate with (key, value).
However i would just make my answer array an array of objects and get rid of all these issues, and it would just be (_note the usage of $index and ng-model):-
<div data-ng-repeat="answer in currentQuestion['possible_answers'] track by $index" class="form-group">
<label class="col-md-3 control-label">Answer {{ $index + 1 }}</label>
<div class="col-md-8">
<div class="input-icon">
<i class="fa fa-sun-o"></i>
<input data-ng-model="answer.text" type="text" class="form-control" >
</div>
</div>
</div>
Demo
The ng-repeat creates a new child scope for each item in the list. In this scope it knows index and answer. You bind the value of the input to something outside the scope, namely the same item in the array. Changing it triggers the list to be redrawn, which causes the input to loose focus.
<div data-ng-repeat="(index, answer) in currentQuestion['possible_answers']" class="form-group">
<label class="col-md-3 control-label">Answer {{ index + 1 }}</label>
<div class="col-md-8">
<div class="input-icon">
<i class="fa fa-sun-o"></i>
<input data-ng-model="answer" type="text" class="form-control" >
</div>
</div>
</div>

In AngularJS, how do I set the selected option from select as a parameter elsewhere on the page?

In AngularJS, how do I get the selected option from a select element to put it somewhere else on the page?
<div class="modal-body">
<form class="">
<div class="control-group">
<label class="control-label" for="role">Choose a Playlist</label>
<div class="controls">
<select name="playlist">
<option ng-repeat="playlist in playlists | orderBy: 'playlist'" value="{{playlist.id}}">{{ playlist.name }}</option>
</select>
</div>
</div>
<p>
Or,
<a class="branded" href="#">Create New Playlist</a>
</p>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-branded" ng-click="postSongToPlaylist();">Save</button>
</div>
I want to get the option the user selects in the select element and put it as the parameter for the ng-click. How do I get Angular to "know" which option is the right one?
The value will be stored in the scope as the name you give to ng-model for the select tag.
<div class="modal-body">
<form class="">
<div class="control-group">
<label class="control-label" for="role">Choose a Playlist</label>
<div class="controls">
<select name="playlist" ng-model="playlist" ng-options="playlist.id as playlist.name for playlist in playlists | orderBy: 'playlist'">
</select>
</div>
</div>
<p>
Or,
<a class="branded" href="#">Create New Playlist</a>
</p>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-branded" ng-click="postSongToPlaylist(playlist);">Save</button>
</div>
I would also suggest that you use ng-options instead of ng-repeat to populate your option tags.

Resources