Changing value of an input date picker with button angular - javascript

I have have an input field which is attached an Angular UI datepicker.
Below that, I added 2 buttons to change date, "day by day".
Here is the input part (just after in my page):
<p class="input-group">
<span class="input-group-addon hidden-xs">From</span>
<input type="text" class="form-control text-center" datepicker-popup="{{format}}" ng-model="parent.dtFrom" ng-change="refresh(0)" show-button-bar="false" is-open="opened1" max-date="maxDate" datepicker-options="dateOptions" ng-required="true" close-text="Close" readonly />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event, 'opened1')"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
And here are my button to change it:
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 btn-group" role="group" >
<div class="text-center" >
<button type="button" class="btn btn-default btn-outline glyphicon glyphicon-chevron-left text-center previousdate" ng-click="addDayFrom(-1)"></button>
<button type="button" class="btn btn-default btn-outline glyphicon glyphicon-home text-center todaydate" ng-click="DateFromToday()"></button>
<button type="button" class="btn btn-default btn-outline glyphicon glyphicon-chevron-right text-center nextdate" ng-click="addDayFrom(1)" ng-show="parent.dtFrom < todate" ></button>
</div>
</div>
Here is how I init my dtFrom at the begin of my controller:
$scope.parent={
dtFrom : new Date(),
dtTo : new Date()
};
And this is my function for change dtFrom:
$scope.addDayFrom=function(day){
$scope.parent.dtFrom.setDate($scope.parent.dtFrom.getDate() + parseInt(day));
console.log($scope.parent.dtFrom);
};
It change value in $scope.parent.dtFrom but model isn't updated into input.
Example: Today we are 12/05/2015.
If I click one time on previous button, $scope.parent.dtFrom will be 11/05/2015.
And that's what is displayed all but the input.
I suppose that's a scope issue, but can't figure out where it is.
Have you any clue to fix this ?
Edit: Picture here : http://hpics.li/4e0fab6

Change your code from:
$scope.addDayFrom=function(day){
$scope.parent.dtFrom.setDate($scope.parent.dtFrom.getDate() + parseInt(day));
console.log($scope.parent.dtFrom);
};
To this:
$scope.addDayFrom=function(day){
$scope.parent.dtFrom = ($scope.parent.dtFrom.getDate() + parseInt(day));
console.log($scope.parent.dtFrom);
};
Looking at the Angular UI datepicker documentation, you can see that you don't need to access parent. I thought you were trying to access the parent scope, but actually you were accessing the parent attribute that you have set here:
$scope.parent={
dtFrom : new Date(),
dtTo : new Date()
};
Angular UI datepicker is watching by reference, as we can see in their source code, what makes perfect sense, since that's the most efficient watching strategy. To understand more about that, read Scope $watch Depths on Angular core documentation:
Scope $watch Depths
Dirty checking can be done with three strategies: By reference, by
collection contents, and by value. The strategies differ in the kinds
of changes they detect, and in their performance characteristics.
Watching by reference (scope.$watch (watchExpression, listener)) detects a change when the whole value returned by the
watch expression switches to a new value. If the value is an array or
an object, changes inside it are not detected. This is the most
efficient strategy.
Watching collection contents (scope.$watchCollection (watchExpression, listener)) detects changes that occur inside an
array or an object: When items are added, removed, or reordered. The
detection is shallow - it does not reach into nested collections.
Watching collection contents is more expensive than watching by
reference, because copies of the collection contents need to be
maintained. However, the strategy attempts to minimize the amount of
copying required.
Watching by value (scope.$watch (watchExpression, listener, true)) detects any change in an arbitrarily nested data
structure. It is the most powerful change detection strategy, but also
the most expensive. A full traversal of the nested data structure is
needed on each digest, and a full copy of it needs to be held in
memory.
That's why it wasn't detecting $scope.parent.dtFrom.setDate(newDate) usage, and the model wasn't being updated. So, just change that piece of code to $scope.parent.dtFrom = newDate, and it should work (as it has already worked with your global variable approach).

It's a bit of hack but, it works ... so I share it with you
When i start my app i create a local date variable that i change when i click on my button. when it's done, i do that :
$scope.parent.dtFrom = new Date(localDateVariable);
Not the best solution, but a solution.

Related

Angular 6 Nested FormArray

I'm trying to make a form with an array of fields generating by clicking '+' using Angular Reactive Forms. However, when I try to use [formControlName]="index" in child component it doesn't work.
Firstly it was saying that formControlName should have a parent with FormGroup I passed it and added. Now it says Cannot find control name with unspecified name attribute. In the Angular docs it's said that one able to use FormArray with [formControlName] and index since there is no names.
This is what I have
https://stackblitz.com/edit/angular-runxfe
I have fixed your issues. You needed to pass the formGroupName here:
<app-site-form-feature
*ngFor="let feature of features.controls; let last = last; let index = index; let first = first" [formGroupName]="index"
[last]="last" [index]="index" [first]="first"
(addFeature)="addFeature()" (removeFeature)="removeFeature(index, first, last)">
</app-site-form-feature>
HTML of the child component will look like this:
<div class="row no-gutters form-group">
<input type="text" class="form-control px-2 col-10">
<span class="btn btn-outline-danger" (click)="removeFeature.emit(index, first, last)">-</span>
<span class="btn btn-success" *ngIf="last" (click)="addFeature.emit($event,index)">+</span>
</div>
Take a look to this stacblitz https://stackblitz.com/edit/angular-v8zkz2
You can also reference this guide:
https://alligator.io/angular/reactive-forms-formarray-dynamic-fields/

I can't edit a object in an array, ng-model doesn't change with ng-click

I am making a movie library. I use ng-repeat to show the movies and, for each movie there is a button to edit it and another one to remove it. The remove button works just fine, but the edit button doesn't.
It should open a panel and fill it with the movie data, but it only opens the panel with the first value I defined for the index.
button
<i class="glyphicon glyphicon-pencil small btnEdit" ng-click="i =(movies.indexOf(movie));"></i>
input
<input type="text" class="form-control" placeholder="Title" id="title" ng-model="movies[i].title">
the whole code is here: https://jsfiddle.net/victoorns/mwgcnsno/2/
Your controller's $scope property 'i' is being hidden via the rules behind scope inheritance. Ng-repeat creates its own isolate scope and since 'i' is a primitive (its just an integer), 'i' is only being set on that child $scope, as opposed to the main parent controller's scope.
<input type="text" class="form-control" placeholder="Title" id="title"
ng-model="movies[selected.movieIndex].title">
<i class="glyphicon glyphicon-pencil small btnEdit"
ng-click="selected.movieIndex =(movies.indexOf(movie));"></i>
Heres an updated jsfiddle here.
Notice how I am using an object (selected.movieIndex) so that is correctly updating the right property.
Heres more on understanding the exact behavior going on with the scope here
Approach is putting too much business logic in the view.
Pass whole object back to controller when you do things like this. Then do any splicing, copying etc in controller:
Simplified example:
<div ng-repeat="movie in movies">
<button ng-click="edit(movie)">
<button ng-click="delete(movie)">
</div>
In controller:
$scope.delete = function(movie){
var idx = $scope.movies.indexOf(movie);
if(idx !=-1){
$scope.movies.splice(idx,1)
}
}
$scope.edit = function(movie){
$scope.selectedMovie = movie;
}
Also get rid of all the jQuery and get rid of bootstrap.js and replace with angular-ui-bootstrap

AngularJS filter distance with input text box

Task
To omit ng-repeat values greater than specified distance(eg:3kms).
I use Angular Filter and using omit in that.
The below code works fine. It removes ng-repeat values with distance greater than 3 kms.
|omit:'distance > 3'
I tried to achieve the same with a button
<p><button class="btn btn-warning btn-block" ng-click="getDistance = 3">Show less than 3kms</button></p>
|omit:'distance > getDistance'
I will try my best to create a jsFiddle, if the question is not clear.
From the documentation given for Angular filter and the description, if you had some collection and wanted to filter based on distance on each element:
<p><button class="btn btn-warning btn-block" ng-click="getDistance = 3">Show less than 3kms</button></p>
<span ng-repeat="obj in collection | omit: distance > getDistance">
{{ obj.someValue }}
</span>
Then make getDistance a field on your $scope and distance a field on each object in collection.
I've not used this but I would think your solution would be similar to this.

Combine ng-repeat and ng-click

I am building an angularJS app using ng-repeat and ng-click on the same element.
I have an array of items which I run through to create a list of buttons. Each one of these items has a property category which I'd like to pass as an argument for an ng-click action.
So far I have used the following code:
<button type="button" class="btn btn-default" ng-repeat="job in jobs" ng-click="filterJobListings(job.category)">
{{ job.category }}
</button>
However, the generated HTML is as follows:
<button type="button" class="btn btn-default ng-scope ng-binding" ng-repeat="job in jobs" ng-click="filterJobListings(job.category)">Design</button>
How can I pass the argument correctly here?
Thanks a lot,
Cheers
EDIT
I was wrong, ng-click="filterJobListings({{job.category}})" is not the solution
I believe you're doing it correctly. This could be an issue with prototypical inheritance. Remember, that ng-repeat creates its own scopes that might not apply their changes to the parent scope(s).
See my fiddle that works. Notice I'm using and object to store the selected category $scope.obj.cat=i;. It wouldn't work if I used a primitive.
http://jsfiddle.net/nicolasmoise/hwH64/

One way binding + dynamic binding in AngularJS

I will start by explaining what we are trying to achieve.
We have just jumped on the Angular bandwagon and are building a prototype with it to see what it is capable of.
Currently there is a load of data (grades in this case) on the server and we display that data using Angular.
The following is the code we use:
<ul class="phones">
<li class="list-group-item" onclick="toggleExpandedView(this, true, 500)" ng-repeat="grade in grades | filter:query | orderBy:orderProp">
<span ng-show="grade.comment"><img src="../Content/images/comment.gif"/></span>
<a class="btn btn-primary editButton" style="float: right; position: absolute; right:10px;" ng-href="#/grades/{{grade.gradeId}}">Edit</a>
<div class="heading1"><a ng-href="{{grade.url}}" target="_blank">{{grade.gradeValue}}</a></div>
<div>Provided by {{grade.assessorFirstname}} {{grade.assessorLastname}} on {{grade.dateModifiedFormatted}} </div>
<div class="expandedGrade" onclick="childDivClick(event)" style="display: none" id="grade-{{grade.gradeId}}">
<label>Attachments</label>{{grade.attachmentCount}}
<br />
<span ng-hide="editing" ng-click="editing = true"><b>{{grade.comment || 'No comments yet'}}</b></span>
<form ng-show="editing" ng-submit="editing = false">
<input type="text" ng-model="grade.comment" placeholder="Comment" ng-required />
<br />
<input id="saveChanges" type="submit" class="btn btn-primary" ng-click="saveChanges(this, grade)" text="Save changes" />
</form>
</div>
</li>
</ul>
As you can see we have a parent ul and for each grade in grades we simply display a li and a div that is hidden and when you click on the li we use jQuery to animate and display the hidden div. In the child div we have a comments field which users can update and click save. On save the current object gets fired back to the server however we are concerned about the fact that Angular has to go through all 2000 grades until it finds the one we are updating (due to two way binding) and this means that everything will be really slow and we cannot afford that.
This is what we want to achieve:
1 We want to bind the data one way so that we can display the list of all grades on the screen and as soon as they are all displayed we want to somehow remove the bindings.
2. When users update the comments for a particular grade we then want to dynamically bind that particular grade so that Angular knows exactly which one it has to update without having to go through the whole collection of 2000+ grades.
I have find a tutorial however I am still unsure how to integrate that into my code.
I have also watched this video and I understand the concept behind it but again, I am struggling to write something that actually works ( we have just started using Angular so I am pretty much a newbie)
Could anyone out there point me in the right direction and provide me with some code samples that would solve the issue we are facing? Any advice and help would be greatly appreciated
You could always use a directive
The logic should go like this
use a service to hold your grades
inject the service into your directive
make a copy and just bind the 'read only view' in your directive
you could watch the service for changes and makes updates as needed
in your directive
as far a lazy loading / updating when needed - use a data service
and call the data service for an update whenever the trigger fires
if your trigger needs to come as a push from some other 'web service' consider a technology
like http://socket.io/
I can put together an example if you would like to see how the services and directives should interact

Categories