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

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));
};

Related

Problem trying to select next item in JQuery

I'm trying to select the next element to add the class image-radio-selected with JQuery.
My html is like
<div id="photocall">
#foreach ($photocalls as $photocall)
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb image-radio-selected"></div>
</div>
#endforeach
<input>
</div>
Im trying to:
$( "#mybutton" ).on("click", function() {
var selected = $('.photocallThumb.image-radio-selected'); // working
selected.next('.photocallThumb').addClass('image-radio-selected'); // not working
});
After 2 hours, trying to solve, reading doc,
I'm more confused than when I started...
what am I doing wrong?
One method is you will need to get out of the parent div, then do a next for the parent.
$( "#mybutton" ).on("click", function() {
var selected = $('.photocallThumb.image-radio-selected');
selected.parent(".d-inline-block").next(".d-inline-block").find('.photocallThumb').addClass('image-radio-selected'); // not working
});
.image-radio-selected{border:1px solid #ff00aa;}
.mx-1{width:100px;height:100px;border:1px solid #000000;}
.d-inline-block{display:inline-block;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="photocall">
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb image-radio-selected"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<button type="button" id="mybutton">next</button>
</div>
JQuery's next method selects the next sibling of the selected element. However, since your photocallThumb div is inside a d-inline-block div, it has no siblings. You'd have to go back up a level, then find the next photocallThumb, maybe something like selected.parent().find('.photocallThumb').eq(0).
However, an even better pattern that will help you avoid bugs like these is called templating. Basically, on the client side, you have an html template string, and you pass it data that represent your current state. In your case, you'd pass it an array of javascript objects, each one with an image url and an isSelected boolean. Then, when your state changes, instead of using jquery to try to fix what's changed, you just rerender your template and replace your html element's content with the newly rendered template, and it's now magically in the correct state. This is the pattern favored by large frameworks like React and Angular.
Here's an example from lodash that renders a list of usernames:
// Use the "evaluate" delimiter to execute JavaScript and generate HTML.
var compiled = _.template(
`<% _.forEach(users, function(user) { %>
<li><%- user %></li>
<% }); %>`);
compiled({ 'users': ['fred', 'barney'] });
// => '<li>fred</li><li>barney</li>'

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;
}

How to verify notify.js alert in selenium

I want to verify the text of notification message which has code like this:
<div class="notifyjs-corner" style="top: 0px; left: 45%;">
<div class="notifyjs-wrapper notifyjs-hidable">
<div class="notifyjs-arrow" style=""/>
<div class="notifyjs-container" style="">
<div class="notifyjs-bootstrap-base notifyjs-bootstrap-success">
<span data-notify-text="">Payment Created Successfully</span>
</div>
</div>
</div>
</div>
My selenium code is:
String notify = BrowserSetup
.driver
.findElement(By.xpath("//span[contains(.,
'Payment Created Successfully')]"))
.getText();
System.out.println(notify);
The value in String notify is empty.
Question
How can I get text of the notification?
For reference: notify.js
Find element by Css Selector
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".notifyjs-bootstrap-base.notifyjs-bootstrap-success>span"))).getText();
String notify= BrowserSetup.driver.findElement(By.cssSelector(".notifyjs-bootstrap-base.notifyjs-bootstrap-success>span")).getText();
System.out.println(notify);
It is working when I find element by cssSelector

Bootstrap collapse function difference between bootstrap v3.3.5 and v2.1.1

I am using bootstrap v3.3.5 in my application and wanted to include collapse function such that, when user clicks on a link, div below it toggles. Referring to answer in this Can you specify a "data-target" for Bootstrap which refers to a sibling DOM element without using an ID? I was able to achieve similar result as my requirement, in the below fiddle link
https://jsfiddle.net/szp1cg0k/, which is using bootstrap v2.1.1.min.js and v2.1.1.min.css
But in the same fiddle when I include bootstrap v3.3.5.min.js and v3.3.5.min.css reference the toggle/collapse functionality doesn't work here, neither throws any error
updated JS https://jsfiddle.net/ohoLxap6/2/
html code:
<fieldset class="fsStyle">
<legend class="legendStyle">
<a data-toggle="collapse-next" data-target=".demo" href="#">Activity Log Filter Criteria4</a>
</legend>
<div class="demo" >
<div class="col-md-2">
<label for="activity_from_date" class="labelStyle">Activity From Date:</label>
</div>
<div class="col-md-4">
<input name="fromDate" maxlength="10" size="11" tabindex="59" value="" onblur="javascript:DateFormat(this,event,true);" class="textInput" id="activity_from_date" type="text">
</div>
</div>
</fieldset>
script:
$('body').on('click.collapse-next.data-api', '[data-toggle=collapse-next]', function() {
console.log($(this).parent());
var $target = $(this).parent().next()
console.log($target);
$target.data('collapse') ? $target.collapse('toggle') : $target.collapse()
});
Can anyone give me some hint where I am going wrong ?
UPDATE:
I am aware of the collapse function of bootstrap, I have multiple divs in my form and I want to include collapse function on most of the divs. One way to achieve this is
<div data-toggle="collapse" data-target="#demo1">
<div id="demo1">
<p>demo 1 ......</p>
</div>
<div data-toggle="collapse" data-target="#demo2">
<div id="demo2">
<p>demo 2 ......</p>
</div>
But I dont want to use ids, instead I want to specify class. The reason being, I have jqtree at backend and I have to include clone function as well, so using ids would mean after cloning I need to take care of ids of cloned child node div. Hence want to use class instead , something like below
<div data-toggle="collapse" data-target=".demo">
<div class="demo">
<p>demo 1 ......</p>
</div>
<div data-toggle="collapse" data-target=".demo">
<div class="demo">
<p>demo 2 ......</p>
</div>
Got this working. I have updated the fiddle accordingly. https://jsfiddle.net/ohoLxap6/3/
$('body').on('click.collapse-next.data-api', '[data-toggle=collapse-next]',
function() {
//console.log($(this).parent());
var $target = $(this).parent().next()
console.log($target);
$target.data('bs.collapse') ? $target.collapse('toggle') :
$target.collapse()
});
Why would you write your own code for a existing Bootstrap function? Following code is an example of the latest Bootstrap version collapse method:
<button class="btn" data-toggle="collapse" data-target="#demo">Collapsible</button>
<div id="demo" class="collapse">
Some text..
</div>
Docs: http://getbootstrap.com/javascript/#collapse
UPDATE:
According to your new question, collapsing using classes, I have created a custom script:
$('[data-toggle="collapse"]').click(function() {
var $target = $(this).data('target');
var $target = $($target);
$target.data('bs.collapse') ? $target.collapse('toggle') :
$target.collapse()
});
Now all classes inside the data-target attribute will get toggled. https://jsfiddle.net/ohoLxap6/4/

trigger ng-click by element id?

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.

Categories