Combine ng-repeat and ng-click - javascript

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/

Related

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

How to show the details of a particular row in a modal when row is clicked in AngularJS

I'm new to AngularJS. I'm converting some pages to AngularJS. I just displayed rows of information. However I'm having trouble converting the button onclick part to AngularJS. Can someone please help me. Below is the code that I'm working with.
<div ng-repeat="i in data">
<p>{{i.name}}</p>
<button class="btn btn-xs btn-default" data-toggle="modal" data-target=".show-ticket-details-modal" onclick="show_details(10)">
<i class="fa fa-info"></i>
</button>
</div>
Just pass the model to show_details method
show_details(i)
Regards,
Try using ng-click (https://docs.angularjs.org/api/ng/directive/ngClick). This runs a function in your angular controller when you click an element. All you've got to do is add the ng-click directive to your element, and then build a function with the same name in your angular controller to handle the data.
IE, replace onclick="show_details(10)" with: ng-click="show_details(10)".
Then, in your controller, build a function with the same name that will handle the data show_details(10), like:
$scope.show_details = function(index) {
console.log(index); // will log 10 in the example above
// do stuff with your index here,
// pass data to your angular factory, etc.
};
Note: For <form> elements, you can use the ng-submit directive instead (https://docs.angularjs.org/api/ng/directive/ngSubmit). Just use ng-submit="someFunction()" instead of ng-click.
Another Idea:
Instead of passing in the number 10, you could also use track by $index (https://docs.angularjs.org/api/ng/directive/ngRepeat#), for example, in your ng-repeat, you could:
ng-repeat="i in data track by $index"
Now, you can actually just pass $index into your ng-click function, instead of the number 10:
ng-click="show_details($index)" // $index will be 10, if the index of `i` was 10 in `data`
Hope this helps somewhat, let me know if you have any questions! The links included show more examples of their usage!

How to pass data from AngularJS list to Bootstrap modal?

At my view I have a list of items:
<li ng-repeat="fruit in items">
{{fruit.name}} / {{fruit.price}}
<button type="button" class="btn btn-info btn-lg" data-toggle="modal" data-target="#myModal">EDIT</button>
</li>
And I'd like to edit each product using bootstrap modal. That's why I need to pass data of specific product to modal. After this I'll simply pass this data to angular script using ng-click="saveFruit(dataFruit)" and saveFruit will save data.
Here is my fiddle:
http://jsfiddle.net/czus6s3a/
EDIT: Changed answer entirely.
Click here for a working fiddle: http://jsfiddle.net/sn8u7kqe/1/.
Changes made:
In the controller, I created a $scope.dataFruit = null, just to ensure the variable is initialized. I also created a function as follows:
$scope.setDataFruit = function(fruit) {
$scope.dataFruit = fruit;
};
This was to ensure that we were assigning our fruit to the right $scope.
Finally, I had you move your <div class="modal"> to INSIDE the div which had the ng-controller directive.
The controller will only apply it's model (variables, and functions, etc), to the elements that it has visibility of. As per your original example, the modal was OUTSIDE of the div, so the data binding would not have applied there.

Changing value of an input date picker with button angular

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.

Angular JS: Unable to set value to ng-model variable inside ng-repeat

I have the below code that is working fine. That is, it is displaying the combobox with Country names in it and when I select a country in the combobox it prints the "Filter Data: "
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click=""><i class="glyphicon glyphicon-globe"></i> Country</button>
<select class="form-control" style="width:200px;" ng-model="filters" ng-options="country.name for country in countries"></select>
</span>
Filter Data: {{filters}}
</div>
In the above code, I declared a scope variable using ng-init="filters" ( not through the Controller ) and I am trying to set the selected combo item to this variable. It worked fine.
I have then replaced the above code with the following ng-repeat code:
<span ng-repeat="filter in filterList">
<button type="button" class="btn btn-default" style="width:75px" ng-click="">{{filter.filterLabel}}</button>
<span ng-switch="filter.filterType">
<span ng-switch-when="combo"><select class="form-control" style="width:200px" ng-model="filters" ng-options="country.name for country in filter.countryData"></select></span>
</span>
</span>
Filter Data: {{filters}}
</div>
The above code though displays the country names in the combobox, when I select a country it doesn't display anything near "Filter Data". I thought may be the scope variable "filters" isn't visible near ng-repeat ( just a guess ) and hence also tried which also didn't work.
Questions:
Can you help me understand why the ng-model="filters" is not setting the scope variable 'filters' and letting me print it?
I would also like to dynamically create the variable name in ng-model. Something like ng-model="filters.{{filter.filterType}}". I tried it but never got any results. It was not displaying the {{filters}}. After going through some posts on Stackoverlow I tried ng-model="filters.[filter.filterLabel]". This actually through some JS errors ( saying TypeError: Cannot set property 'Country' of undefined) when I selected an item in the country combo. It seems it wasn't able to find Country ( which is result of [filter.filterLabel] ) inside filters. So there is obviously something quite wrong with the way I am declaring the ng-model.
With the above code ( where I want to use the scope variable ng-init="filters" ), can you help me the correct way to dynamically generate the ng-model variable names for the item selected and be able to use {{filters}}
UPDATE:
Here is the Fiddle to demonstrate my problem: http://jsfiddle.net/ramarajuv/ag2crnk7/
Please help me by correcting it.
Thank you all in advance.
Got it working.
First, created filters variable in the scope of the controller:
$scope.filters = {
"Country":{},
"President of Country":{}
};
Then, formatted ng-model as:
ng-model="filters[filter.filterMap]

Categories