How to access nested object info for nested functions - javascript

I'm writing an app in Angular and have something like this:
$scope.items = [
{'name':'someName',
'title': 'someTitle',
'filter': function(item){
Filters.setTableTitle(this.title); //cannot get title
...
}
},
{'name':'someName',
'title': 'someTitle',
'filter': function(item){
Filters.setTableTitle(this.title);
...
}
}
];
An array of objects. Part of each object is a function, and inside the function I would like to call a function that grabs the title of that object itself in order to pass it into a greater scope for the rest of the app.
However, I can't grab the title for each object.
How would I access the title in order to use it here?
Thanks.
Update
Here is my HTML that uses (something very similar to) the code above. I'm using the code to create buttons.
<p ng-repeat="link in items">
<block class="button" href="{{link.URL}}" title="{{link.title}}">
<a class="hrefLink" href="{{link.URL}}" ng-click="Filters.setFilter(link.filter, link.title)">
{{link.name}}
</a>
</block>
</p>
The function held within the filter part of each object returns information that is then passed into Filters.setFilter() which updates the DOM.
Filters.setFilter()
service.setFilter = function(filter, title){
service.searchTerm = '';
$spMenu.hide(); //close nav if open
service.selectedFilter = filter;
service.setTableTitle(title); //this does the job
};
I've rearranged the ways these functions work, and now simply pass in the title to the different functions. This gets the job done for what I want, but still could never solve the initial question at hand--how would I access part of an object from inside the object?

I don't know Angular wery well so there could definitely be a much better soultion.
If you call the function yourself, just write it like this:
$scope.items[x].filter(item);
If it's called somewhere else and this doesn't contain the right object, you can enumerate all objects and bind the function to it:
for (var i = 0; i < $scope.items.length; ++i) {
var item = $scope.items[i];
item.filter = item.filter.bind(item);
}
Edit:
You have two choices. First you can just bind the function in HTML:
<p ng-repeat="link in items">
<block class="button" href="{{link.URL}}" title="{{link.title}}">
<a class="hrefLink" href="{{link.URL}}" ng-click="Filters.setFilter(link.filter.bind(link))">
{{link.name}}
</a>
</block>
</p>
Or you can edit the function to do it for you:
<p ng-repeat="link in items">
<block class="button" href="{{link.URL}}" title="{{link.title}}">
<a class="hrefLink" href="{{link.URL}}" ng-click="Filters.setFilter(link)">
{{link.name}}
</a>
</block>
</p>
service.setFilter = function(link){
service.searchTerm = '';
$spMenu.hide(); //close nav if open
service.selectedFilter = link.filter.bind(link);
};

Related

Calling a text/x-kendo-template script type from a javascript function

I have this new button and on onclick event I'm calling function openEditor(), and inside this function I want to call a text/x-kendo-template script type. How can I do this?
My code right now:
Custom button:
schedulerToolbar.append(
"<ul class='k-reset'>
<li class='k-state-default'>
<a role='button' href='#' class='k-link newMeetingButton' onclick='openEditor()'>
Nova reserva
</a>
</li>
</ul>"
)
Function openEditor():
function openEditor() {
*code to call customEditorTemplateBh script*
}
Template script:
<script id="customEditorTemplateBh" type="text/x-kendo-template">
*template code*
</script>
edit: I'm using a kendo scheduler and I've added that custom button on toolbar.
You can access this by using kendo.template() supplying the selected id reference to your template, in your case:
var template = kendo.template($("#customEditorTemplateBh").html());
From here you can supply any required data for your template by calling template as a function:
var data = {Attribute1: "Test", Attribute2: Test2};
var result = template(data);
And finally, update your view by setting the html of whatever <div> you are using to the result:
$("#nameOfYourDivHere").html(result);
Reference material for templates can be found here.
The following code was enough:
var scheduler = $("#scheduler-bh").data("kendoScheduler");
scheduler.addEvent({ });

Remove item from array by pressing button

I'm using angularJS to build a SPA. I am trying to delete an object from an array in my controller. I am using ng-repeat and can't seem to get my head around this. Here is the related html:
<div class="cat-button" ng-repeat="category in cats" category="category">
<button class=" close-button" ng-click="removeCat()">
<span class="glyphicon glyphicon-remove-sign" aria-hidden=true> </span> </button>{{category.name}}
</div>
This created a div with a button for every object that gets saved to my $scope.cats array. It works fine but I cant figure out how do I use the button in each div to delete that specific object.
When I click on the button , the function on my controller gets called, but this is where I get lost, how do I delete the specific object created dynamically by the user.
This is the related code on my controller:
//Function to delete category
$scope.removeCat = function () {
//I know I have to use splice on my array but how do I Identify the object that needs to be deleted from my array?
};
You can either pass on $index like so:
<button class=" close-button" ng-click="removeCat($index)">
and in your function:
$scope.removeCat = function (index) {
$scope.cats.splice(index,1);
}
or pass the whole item and use indexOf (the saver way)
<button class=" close-button" ng-click="removeCat(category)">
$scope.removeCat = function (item) {
$scope.cats.splice(myArray.indexOf(item), 1);
}
You can pass the index of the item you want to delete in the ng-click function:
<div class="cat-button" ng-repeat="category in cats" category="category">
<button class=" close-button" ng-click="removeCat($index)">
<span class="glyphicon glyphicon-remove-sign" aria-hidden=true> </span> </button>{{category.name}}
</div>
Then you can use this in your Angular controller like this:
$scope.removeCat = function (index) {
$scope.cats.splice(index, 1);
};
Update
Incase you don't want to pass in the index, instead you can also pass in the entire object and locate the index in your controller. The code below is setup to work on all browsers. (Just haven't tested it ;) )
$scope.removeCat = function (cat) {
// Using underscore
var index = _.indexOf($scope.cats, cat);
// Or using a for loop
for(var i = 0; i < $scope.cats.length; i++) {
//Assuming your cat object has an id property
if($scope.cats.id === cat.id) {
index = i;
break;
}
}
};
Or any other way to locate the index of an object in an array.
ng-click="removeCat(category)"
$scope.removeCat = function (categoryToDelete) {
var index = $scope.cats.indexOf(categoryToDelete);
$scope.cats.splice(index, 1);
};

binding to controller object in Angular

I'm new to angular, trying to bind an an element's content into the controller's Scope to be able to use it within another function:
here is the scenario am working around:
I want the content of the <span> element {{y.facetName}} in
<span ng-model="columnFacetname">{{y.facetName}}</span>
to be sent to the controller an be put in the object $scope.columnFacetname in the controller
Here is a snippet of what I'm working on:
<div ng-repeat="y in x.facetArr|limitTo: limit track by $index ">
<div class="list_items panel-body ">
<button class="ButtonforAccordion" ng-click="ListClicktnColumnFilterfunc(); onServerSideButtonItemsRequested(ListClicktnColumnFilter, myOrderBy)">
<span>{{$index+1}}</span>
<span ng-model="columnFacetname">{{y.facetName}}</span>
<span>{{y.facetValue}}</span>
</button>
</div>
</div>
angular.module('mainModule').controller('MainCtrl', function($scope, $http) {
$scope.columnFacetname = "";
$scope.ListClicktnColumnFilter = "";
$scope.ListClicktnColumnFilterfunc = function() {
$scope.ListClicktnColumnFilter = "\":\'" + $scope.columnFacetname + "\'";
};
}
the problem is that the $scope.ListClicktnColumnFilter doesn't show the $scope.columnFacetname within it, meaning that the $scope.columnFacetname is not well-binded.
In your ng-click instead of calling two different function
ng-click="ListClicktnColumnFilterfunc(); onServerSideButtonItemsRequested(ListClicktnColumnFilter, myOrderBy)"
you can declare like this
ng-click="columnFacetname = y.facetName; onServerSideButtonItemsRequested(columnFacetname , myOrderBy)"
You are trying to pass that model to another function by assigning it to ListClicktnColumnFilter in your controller
By doing in this way, you can achieve the same thing.
I have done one plunker with sample array,
http://embed.plnkr.co/YIwRLWXEOeK8NmYmT6VK/preview
Hope this helps!

adding array elements to another array

I have a very big list which is an array named leagues, I need to allow the user to take the elements on that array(list) , and choose those as favorites by clicking a button
$scope.favoriteLeagues = [];
$scope.favoriteLeague = function(league) {
$scope.favoriteLeagues.push(league);
}
so I want to know what am I doing wrong ? the function sometimes allows me to add one as favorite, but once I click on the second one, I got a message of something undefined, and also, the binding is not working, I am unable to see the {{favoriteLeagues.name}} printed.
UPDATED AS REQUESTED
<div>
<strong>Favorites</strong>
{{favoriteLeagues.name}}
</div>
<ion-option-button class="button-light icon ion-star"
on-tap="favoriteLeague(league)">
</ion-option-button>
<div ng-repeat="sport in sportsFilter = (sports | filter:query)">
<strong>{{sport.name}}</strong>
</div>
<ion-item ng-repeat="league in sport.leagues">
<div>{{league.name}}</div>
</ion-item>
</ion-list>
here the controller:
.controller('SportsController', function($scope, $state,
AuthFactory, SportsFactory) {
$scope.favoriteLeagues = [];
$scope.sports = [];
AuthFactory.getCustomer().then(function(customer) {
$scope.customer = customer;
SportsFactory.getSportsWithLeagues(customer).then(function(sports) {
if (sports.length) {
$scope.sports = sports;
}
$scope.isSportShown = function(sport) {
return $scope.shownSport === sport;
};
$scope.favoriteLeague = function(league) {
$scope.favoriteLeagues.push(league);
}
};
});
You haven't pasted the full html, but it should look something like this:
<!-- Use ng-app to auto-bootstrap an AngularJS application-->
<!-- Use ng-controller to attach your view with your SportsController controller -->
<ion-list>
<div>
<strong>Favorites</strong>
<!-- Looping through all the favourite leagues-->
<div ng-repeat="favouriteL in favoriteLeagues">
{{favouriteL.name}}
</div>
</div>
<!-- Looping through all the sports -->
<div ng-repeat="sport in sportsFilter = (sports | filter:query)">
<!-- Bind the sport name -->
<strong>{{sport.name}}</strong>
<!-- Looping through all the leagues -->
<ion-item ng-repeat="league in sport.leagues">
<!-- Display a button which on tap will call favoriteLeague function -->
<ion-option-button class="button-light icon ion-star" on-tap="favoriteLeague(league)">
</ion-option-button>
<!-- Bind the name of the league -->
<div>{{league.name}}</div>
</ion-item>
</div>
</ion-list>
Don't forget to attach the view with your controller using ng-controller.
I can't help you much with angular.js, I've never used it, but the fact that you are accidentally replacing the array with the function probably doesn't help. ng-repeat is trying to loop through favoriteLeagues but fails because that's a function! Look at the comments I put in your code.
$scope.favoriteLeague = []; // creates an array
$scope.favoriteLeague = function(league) { // replaces the array with a function!!!
$scope.favoriteLeagues.push(league); // suddenly leagues takes an S ?
}
To avoid this type of error, you should respect a naming convention for your functions. I like to use action words and verbs for functions. I only use plural forms on arrays and related functions. Here's what I'd do in your case:
$scope.favoriteLeagues = [];
$scope.addToFavoriteLeagues = function(league) {
$scope.favoriteLeagues.push(league);
}
You need to attach your controller to the html in order for the bind to work, usually at the top level parent element, e.g a div, containing the ngrepeat markup.

Is there a way to pass a variable with curly brace template tags through a method?

I have an ng-repeat where I run an ng-if with a method that checks to see if certain parameters match between two sets of data. If there's a match, it updates $scope with the current match, which I can use to output my template:
<div ng-repeat="repeatedItem in repeatedItems">
<a href="" ng-if="!matchData(repeatedItem.item1, repeatedItem.item2)">
<img ng-src="{{ matchedItem.falseImageUrl }}" />
</a>
<a href="" ng-if="matchData(repeatedItem.item1, repeatedItem.item2)" ng-click="open(matchedItem.id)">
<img ng-src="{{ matchedItem.imageUrl }}" />
<time>{{ matchedItem.date }}</time>
<div class="button-wrapper">
<button class="btn">{{ matchedItem.text }}</button>
</div>
</a>
</div>
The thinking is that everything out of repeatedItems needed to show, unless an item in repeatedItem matched another data set, in which case you'd show the matchedItem instead.
Everything works fine, except for the ng-click="open(matchedItem.id) bit. Because matchedItem.id isn't wrapped in template tags, ng-click is always calling the latest iteration of matchedItem, so for all but the last repeated element, it's opening the wrong link.
The most obvious solution in my Angular-inexperienced mind would have been to do something like ng-click="open( {{ matchedItem.id }} ), but that throws an error. My next idea was something like ng-click="open( {0} ):{{ matchedItem.id }} - a printf-type of solution, but I haven't found any built-in Angular solution for that. I also thought about stashing {{ matchedItem.id }} in an attribute somewhere (data-id="{{ matchedItem.id }}"?), but I'm not sure how to call that attribute in the method.
It's possible (probable?) that I'm just not "thinking in Angular" yet, and I'm going about this the wrong way entirely. Or perhaps there's a directive that I'm just not aware of?
Here's the method:
$scope.matchData = function(item1, item2) {
var isItAMatch = false;
for (i=0; i<$scope.repeatedItems.length; i++) {
itemAToMatch = $scope.repeatedItems[i].itemA;
itemBToMatch = $scope.repeatedItems[i].itemB;
if (itemAToMatch == item1 && itemBToMatch == item2) {
isItAMatch = true;
$scope.matchedItem = $scope.repeatedItems[i];
break;
}
}
return isItAMatch;
}

Categories

Resources