trigger ng-click by element id? - javascript

Ok i have a ng-repeat iterating over a array passing the $index to a ng-click inside the ng repeat like so:
<div class="animate-repeat row" ng-repeat="items in sortedTypes">
<div class="allinfo" id="idwrap-{{items.id}}" ng-click="shohidifelse($index)">
<div class="allinfo" id="idwrap-{{items.id}}" ng-click="shohidifelse($index)">
<div class="groupcontent row" ng-hide="showhideinfo[$index]">
<div class="large-2 columns">
<p>{{items.phoneTwo}}</p>
</div>
</div>
<div class="row fullprofile" ng-show="showhideinfo[$index]">
<p>{{items.ContactFirst}}</p>
</div>
</div>
</div>
I need to call a click on this
<div class="allinfo" id="idwrap-{{items.id}}" ng-click="shohidifelse($index)">
programatically. i am scroll to this item by the {{items.id}} and i need to call this ng-click from the scroll function.
Is there a clean way to do this, that I've just missed?

answered my own question!
jQuery("#accntselect").on("change", function(e) {
if (!e.added){
}else{
angular.element('#idwrap-'+e.added.id).triggerHandler('click');
jQuery('#idwrap-'+e.added.id).trigger('click').trigger('click');
scrollToAnchor('idwrap-'+e.added.id);
}
});
Where e.added.id is the rest of the element's id!

Try this:
Call the function shohidifelse(), from the jquery scroll function. If you need the $index value to be passed on to shohidifelse(), then pass it on to the jquery function and pass it as a parameter.

Related

How to get the child element value using $event in AngularJS?

I am using the $event.currentTarget to get the element on ng-click as shown below:
<div ng-click="eventHandler($event)" class="bg-master m-b-10" id="slider-tooltips" nouislider=""></div>
In my controller when in console am getting:
<div ng-click="eventHandler($event)" class="bg-master m-b-10 noUi-target noUi-ltr noUi-horizontal noUi-connect" id="slider-tooltips" nouislider="">
<div class="noUi-base">
<div class="noUi-origin noUi-background" style="left: 9%;">
<div class="noUi-handle noUi-handle-lower">
<div class="tooltip fade top in" style="top: -33px;left: -14px;opacity: 0.7;">
<div class="tooltip-inner">
<span>9.00</span>
</div>
</div>
</div>
</div>
</div>
</div>
I am trying to get the value 9 in the above to show as result. How can I do this in AngularJS?
If this method is wrong, then please let me know the right one.
Well, I don't know if this is the best way to go about it, but you can get it from the click event. This worked for me:
$scope.eventHandler = function(e) {
console.log(e.srcElement.children[0].firstElementChild.style.left);
};
I tried below code and i got the result which i was looking for
$scope.eventHandler = function($event){
console.log(parseInt($event.currentTarget.childNodes[0].textContent));
};

Trigger ng-click inside ng-repeat when ng-repeat item.length=1

I want to trigger automatic loadProduct function when products.length==1
Bellow my angular code.
<div class="prodItem prodItem-nos-{{products.length}} prodItem-item-number-{{$index}}"
ng-repeat="product in products track by $index"
ng-click="loadProduct(product.id)"
uib-tooltip="{{ product.name }}">
<div class="prodMeta">
<div class="prodName" ng-bind="product.name"></div>
<div class="prodDescr" ng-bind="product.description"></div>
</div>
<div class="prodBuyNow">
<button ng-click="loadProduct(product.id)">Choose</button>
</div>
</div>
If you want to trigger function when item in scope changes you can use scope.$watch()
for example :
scope.$watch('products',function(oldValue,newValue){
if(newValue.length === 1){
executeFunction();
}
});
See :
https://docs.angularjs.org/api/ng/type/$rootScope.Scope
ng-click="if(products.length === 1){ loadProduct(product.id); }"
I don't like too much conditions inside ng-click. Being products a scope variable, you can just add this logic inside your loadProduct function, adding a condition at the beginning like
if($scope.products.length === 1)
and then execute your code.
If, you want to call loadProduct() is only one product is there call it in api which fetched the products
Eg:
$http.get("/api/products")
.then(function(response) {
$scope.products = response.data;
if($scope.products.length == 1)
{
$scope.loadProduct($scope.products[0].id)
}
});
you can use ng-init function
and check your prodt list in the function
<div ng-repeat="product in products track by $index" ng-init="yourFunctionName()">
<div class="prodMeta">
<div class="prodName" ng-bind="product.name"></div>
<div class="prodDescr" ng-bind="product.description"></div>
</div>
<div class="prodBuyNow"><button ng-click="loadProduct(product.id)">Choose</button></div>
</div>
</div>

Retain scroll position when a button is toggled

I am working on an angularJS application which has a page where I display around 30 items using ng-repeat. In front of each item, there is a toggle button (enabled/disabled). With the current code that I have, I can toggle these items. But the problem is if I scroll down and toggle lets say item 25, then automatically it scrolls to the top of the page. If I now scroll down, I can see that the toggle actually took place.
So the requirement now is to make sure that the scroll position is retained after the toggle button is clicked.
Please see below the code that I have.
HTML
<div id="eventTypes" class="panel-body">
<div ng-if="!spinner" ng-repeat="item in items" class="panel-body">
<div class="row">
<div class="col-md-9">{{item.itemName)}}</div>
<div class="col-md-3">
<input id="toggleEnabled"
type="button"
ng-class="{'btn-primary': item.enabled}"
value="{{item.enabled ? 'enabled' : 'disabled'}}"
ng-click="toggleEnabled(item)">
</div>
</div>
</div>
<div ng-if="spinner" class="spinner">
<div class="spinner-container container1">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
<div class="spinner-container container2">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
<div class="spinner-container container3">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
</div>
</div>
JS
(function () {
'use strict';
angular.module('myApp').controller('itemsController', function ($scope, itemsService) {
var serviceError = function (errorMsg) {
console.log(errorMsg);
$scope.turnOffSpinner();
};
$scope.items = [];
$scope.item = {};
$scope.spinner = true;
$scope.toggleEnabled = function (item) {
$scope.turnOnSpinner();
itemsService.toggleEnabled(item)
.then(function () {
$scope.loaditems();
});
};
$scope.loaditems = function () {
itemsService.getitems().then(function (response) {
$scope.items = response.data;
}, serviceError);
$scope.turnOffSpinner();
};
$scope.turnOnSpinner = function () {
$scope.spinner = true;
};
$scope.turnOffSpinner = function () {
$scope.spinner = false;
};
$scope.loaditems();
});
}());
How this works right now is, once I click the toggle button, a spinner is enabled. Meanwhile the controller will call the itemService.toggleEnabled() method which does an ajax call to the server to just change the status of the item(enabled to disabled or vice-versa) in the backend. On successful change of the status and when the ajax call returns, the $scope.loadItems() method is called in the controller. This method will then do another ajax call to fetch the items (now with the updated status of the item that was toggled). The spinner is disabled and the data is then displayed on the UI.
When all of this is done, the page is scrolled to the top. This is annoying when I want to toggle an item which is way down in the list.
I want the page to be present at the same position when I clicked the toggle button of the corresponding item and not scrolling up to the top.
I am new to AngularJS and any help in this regard would be really helpful.
It looks like your spinner scheme is what's causing you problems:
...
<div ng-if="!spinner" ng-repeat="item in items" class="panel-body">
...
<div ng-if="spinner" class="spinner">
...
Whenever you click your button, you are removing every single element in your ng-repeat from the DOM when you $scope.turnOnSpinner(). That's why it appears to jump to the top. It's not really jumping, there just aren't enough DOM elements to fill up the page, making the page so short that the scrollbar disappears (even if it's only for a second). Then when the spinner is done, your ng-repeat fills up the page with DOM elements again, resulting in your scroll position being lost.
So basically what you are trying to fix is a symptom of a less than ideal loading spinner implementation.
ng-if is a "brutal" way of hiding things in Angular. It's mostly meant to hide things for a longer period of time than "softer" directives like ng-show/ng-hide. One solution to your problem is to use ng-disabled on each one of your buttons to prevent the user from interacting with it while the spinner is active, rather than doing a hard removal of each element:
Before:
<div ng-if="!spinner" ng-repeat="item in items" class="panel-body">
<div class="row">
<div class="col-md-9">{{item.itemName)}}</div>
<div class="col-md-3">
<input id="toggleEnabled"
type="button"
ng-class="{'btn-primary': item.enabled}"
value="{{item.enabled ? 'enabled' : 'disabled'}}"
ng-click="toggleEnabled(item)">
</div>
</div>
</div>
After:
<div ng-repeat="item in items" class="panel-body">
<div class="row">
<div class="col-md-9">{{item.itemName)}}</div>
<div class="col-md-3">
<input id="toggleEnabled"
ng-disabled="spinner"
type="button"
ng-class="{'btn-primary': item.enabled}"
value="{{item.enabled ? 'enabled' : 'disabled'}}"
ng-click="toggleEnabled(item)">
</div>
</div>
</div>
Another solution, which I really like and use myself is this Angular module: https://github.com/darthwade/angular-loading
You can attach it to any element in the page and it will put a loading spinner over it and prevent you from interacting with it until your ajax or whatever is done.
If you don't like either of those, try putting your ng-repeat into a container that you can use to prevent interaction with your elements when the spinner is up:
<div class="container" ng-class="{'you-cant-touch-this': spinner}">
<div ng-repeat="item in items" class="panel-body">
<div class="row">
<div class="col-md-9">{{item.itemName)}}</div>
<div class="col-md-3">
<input id="toggleEnabled"
type="button"
ng-class="{'btn-primary': item.enabled}"
value="{{item.enabled ? 'enabled' : 'disabled'}}"
ng-click="toggleEnabled(item)">
</div>
</div>
</div>
</div>
Now you can style it in some way to prevent interaction without having to remove all those items from the DOM:
.you-cant-touch-this {
pointer-events: none;
}

add a class to element in ng-repeat after some event

I'm making a playlist. I have this ng-repeat where the current song is highlighted
<div ng-repeat="song in songs_list">
<div ng-class="{'true':'current-song'}[song == current_song]">
{{song.title}}
</div>
</div>
now in JS I change the value of current_song. I want to apply the class current-song to the new element which is now playing currently.
On change of song set $scope.current_song to the new song and in the HTML:
<div ng-repeat="song in songs_list">
<div ng-class="{'current-song':song===current_song}">
{{song.title}}
</div>
</div>
you should write like this
<div ng-repeat="song in songs_list">
<div ng-class="{'current-song': song == current_song}">
{{song.title}}
</div>
</div>
Use this syntax, Try with this
<div ng-repeat="song in songs_list">
<div ng-class="{'current-song':song.title == current_song}">
{{song.title}}
</div>
</div>
I suggest, use song.id instead of to song.title and keep id of current_song as song id.
The way ng-repeat works is, it creates a child scope which is prototypically inherited from current scope. Therefore inner current_song value would not update per that. I don't want to repeat answer again why it is not working, you can find explanation here. You have to use Dot Rule in order to get correct selected current_song value inside ng-repeat, & while having condition you should compare it with its unique_id (assuming you have id prop here).
$scope.model = {
current_song: null
};
HTML
<div ng-repeat="song in songs_list">
<div ng-class="{'current-song': song.id == model.current_song.id}">
{{song.title}}
</div>
</div>

ng-repeat: showing an item on click and hiding the others

I have a ng-repeat which display a list of divs and when I click on one it shows an aditionnal div for the clicked item.
This is working
<div ng-repeat="item in items">
<div ng-click="showfull = !showfull">
<div>
<h1>{{item.title}}</h1>
<p>{{item.content}}</p>
</div>
</div>
<div ng-show="showfull">
<p>{{item.info}}</p>
</div>
<hr/>
</div>
My items are loaded from a json containing a list of item and each item have a default attribut showfull set to false in this json. This is working, but now I want to hide all others item in the list when an item is clicked. I've tryied something like this :
This is not working
<div ng-repeat="item in items">
<div ng-click="expand(item)">
<div>
<h1>{{item.title}}</h1>
<p>{{item.content}}</p>
</div>
</div>
<div ng-show="showfull">
<p>{{item.info}}</p>
</div>
<hr/>
</div>
and in the controller I've added a function :
$scope.expand = function(e) {
e.showfull = !e.showfull;
//TODO: put here a foreach logic to hide all other items
}
But even without the foreach logic this is not working, the item don't show the additionnal div when clicked. I have two question :
I suppose this is due to item being "passed by copy" in the expand function or some kind of scope isolation issue but can you explain me why in detail ?
SOLVED
How can I hide all the additional div of other items when I click an item and show the additionnal content for this item ? Do I need to do a directive ?
NOT SOLVED
Thanks
I think you're on the right track. You need to set the showfull on the item and then use ng-show or ng-if to hide it, or as Gavin mentioned, use a class.
On ng-click you can call your expand function, where you pass the item, toggle it and set all others to hidden.
Template:
<div ng-repeat="item in items>
<div ng-click="expand(item)">
<div>
<h1>{{item.title}}</h1>
<p>{{item.content}}</p>
</div>
</div>
<div ng-show="item.showfull">
<p>{{item.info}}</p>
</div>
<hr/>
</div>
Controller:
$scope.expand = function (item) {
angular.forEach($scope.items, function (currentItem) {
currentItem.showfull = currentItem === item && !currentItem.showfull;
});
};
Your expand method is modifying the item, so your ng-show needs to reference the item:
<div ng-show="item.showfull">
<p>{{item.info}}</p>
</div>
To hide all of your items you need to do something like
$scope.expand = function(item) {
angular.forEach(items, function(i) {
if (i === item) {
i.showfull = !i.showfull;
} else {
i.showfull = false;
}
});
};
Shouldn't the second div you want to show be referencing the item?
<div ng-repeat="item in items>
<div ng-click="expand(item)">
<div>
<h1>{{item.title}}</h1>
<p>{{item.content}}</p>
</div>
</div>
<!-- Added item to ng-show -->
<div ng-show="item.showfull">
<p>{{item.info}}</p>
</div>
<hr/>
</div>

Categories