I was wondering how I would go about finding and replacing some text in a div, but i want to find and replace the second occurrence of that text. For example:"You just added a item, please remove this item" so I would like to find the second "item" and replace it with whatever text I choose.
JS:
var compareCount = $('.compareWidget').find('.compareItem').length;
if (compareCount >= 2) {
$('.message').find('.count').text(compareCount);
$('message').html().replace('item', 'items');
}
$('.message').slideDown("Fast");
setTimeout(function () {
$('.message').slideUp("Fast");
}, 5000);
HTML:
<div id="alertMessage">
<div class="message">
<span>You just added a item to compare, you currently have <span class="count">1</span> item to compare</span>
</div>
</div>
"you currently have 1 item to compare"
You want to turn item to items?
You can do it with regular expressions, or you can wrap it into an element and grab that.
<span class="count">1</span> <span class="type">item</span> to compare</span>
and
$('.message').find('.type').text("items");
Using regular expressions you can
function replaceMatch(originalString, searchFor , replaceWith, matchNumber)
{
var match = 0;
return originalString.replace(searchFor, function(found){
match++;
return (match===matchNumber)?replaceWith:found;
},'g');
}
and call it like
var msg = $('.message');
msg.html( replaceMatch( msg.html(), 'item', 'items', 2) );
demo http://jsfiddle.net/gaby/crhvA/
Related
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);
};
This code doesn't work
var next = $("#orders").find(".next");
if (next.length == 1) {
var address = $(next[0]).find(".directionsAddress");
var destination = $(address[0]).text();
}
<div id="orders" class="ui-sortable">
<div id="companyAddress" class="noDisplay">101 Billerica Avenue, North Billerica, MA</div>
<div id="companyPhone" class="noDisplay">9788353181</div><div class="next"></div>
<div class="lat">42.616007</div>
<div class="lng">-71.31187</div>
<div id="section1611" class="sectionMargin borderRad">
<div class="directionsAddress noDisplay">92+Swan+Street+Lowell+MA</div>
It is suppose to find one div with a class of "next" that I know exists on the page, then within that one item of the result set array, there will be one div with a class name of directionsAddress.
The "next" array is coming back with a length of 1, so it looks like the problem is with my $(next[0]).find because the address array is coming back as 0 length and I am making a syntax error of some sort that I don't understand.
This should do what you want. You need to find the parent (or alternatively, the sibling of .next) then try to find the applicable .directionsAddress.
var next = $("#orders").find(".next");
if (next.length == 1) {
var destination = $(next).parent().find(".directionsAddress");
alert($(destination).text());
}
Working fiddle: https://jsfiddle.net/00fgpv6L/
I am new to automated testing, Protractor, and angularJS. I have a list that I would like to count, copy to an array maybe, and verify the list text is present. For example The list shows Attractions, Capacity, and Content to the user so they know what privileges they have.
Below is the .html
<div class="home-info">
<div class="home-top home-section">
<h3>User Information</h3>
<div class="home-box">
<div class="property-group wide">
<span>
Change Phillips<br />
</span>
</div>
</div>
<div class="home-box">
<div class="property-group wide">
<div>Editors:</div>
<span>
<ul class="property-stack">
<li><span>Attractions</span>
</li>
<li><span>Capacity</span>
</li>
<li><span>Content</span>
</li>
<li><span>Media</span>
</li>
<li><span>Options</span>
</li>
<li></li>
<li></li>
<li><span>Upload CADs</span>
</li>
</ul>
</span>
</div>
</div>
</div>
Below is the code I have written. I can get the first item on the list however using .all isn't working for me.
var text = "";
browser.driver.findElement.all(By.xpath("//li/span")).count().then(function(count) {
initialCount = count;
console.log(initialCount);
});
browser.driver.findElement(By.xpath("//li/span")).getText().then(function(text) {
console.log(text);
});
I'm trying to avoid using xpath as I was told to try and avoid. To be honest Im lost. Thanks for the help in advance.
Code used for matching:
expect(myLists).toEqual(['Attractions', 'Capacity', 'Conent',
'Media', 'Options', 'Upload CADs'
]);
I am not sure what version of protractor you're using but you should be able to just call element without the browser or driver prefix. Using element.all should get you the array of of elements you're looking for.
If you want to access specific indexes within that array you can use the .get(index) suffix to the element.all
So below:
1. you get the array of the elements
2. you get the count of the array
3. we call a for loop to iterate through all the indexes of the array
4. each index of the array we call the getText() and print it to the console
var j = 0; // using this since the i iterator in the for loop doesn't work within a then function
var textList = [];
var text = "";
var myLists = element.all(by.css("li span"));
myLists.count().then(function(count) {
console.log(count);
for(int i = 0; i < count; i++){
myLists.get(i).getText().then(function(text) {
textList[j++] = text;
console.log(text);
});
}
});
EDIT:
In researching I actually found another way to iterate through the array of elements by using the .each() suffix to the element.all.
var j = 0; // using this since the i iterator in the for loop doesn't work within a then function
var textList = [];
var text = "";
var myLists = element.all(by.css("li span"));
myLists.count().then(function(count) {
console.log(count);
myLists.each(function(element, index) {
element.getText().then(function (text) {
textList[j++] = text;
console.log(index, text);
});
});
});
you should be able to use the textList array to match things.
expect(textList).toEqual(['Attractions', 'Capacity', 'Conent',
'Media', 'Options', 'Upload CADs'
]);
I know I can use jQuery's .filter() for filtering by attribute. I also know that usage of such custom attributes is frowned upon since W3C's official implementation of data-thing in HTML5.
But I still want to know why this is not working.
JS:
$("[id^=hide]").click(function() {
var lvl = $(this).attr('lvl');
var id = $(this).attr('tar');
$('#' + id).slideToggle(100);
$('div').filter(function(lvl) {
return $('this').attr('lvl') > lvl;
}).slideToggle(100);
});
HTML:
<a id="hide1" lvl="0" tar="1"></a>
<div id="1" lvl="0"></div>
<a id="hide2" lvl="1" tar="2"></a>
<div id="2" lvl="1"></div>
<a id="hide3" lvl="2" tar="3"></a>
<div id="3" lvl="2"></div>
<a id="hide4" lvl="2" tar="4"></a>
<div id="4" lvl="2"></div>
<a id="hide5" lvl="1" tar="5"></a>
<div id="5" lvl="1"></div>
<a id="hide7" lvl="2" tar="7"></a>
<div id="7" lvl="2"></div>
What I want to achieve is.
1. Click on the link.
2. SlideToggle the div that is close to the link.
3. SlideToggle all other divs that have level attribute bigger than level attribute of that link.
I was also trying to do it like this:
$("[id^=hide]").click(function() {
var lvl = $(this).attr('lvl');
var id = $(this).attr('tar');
$('#' + id).slideToggle(100);
hideOthers(lvl);
});
var hideOthers = function(lvl) {
$('div').filter(function(lvl) {
return $('this').attr('lvl')> lvl;
}).slideToggle(100);
}
But that's also not working. Any ideas?
Updated Fiddle
In this line on your code :
$('div').filter(function(lvl) {
The lvl considered as index in jquery filter() function, so the value of lvl inside the function is [ 0 - 1 - 2 .... nbr_of_divs ].
to fix that just remove lvl from param and use it directly.
$('div').filter(function() {
return $(this).attr('lvl') > lvl;
}).slideToggle(100);
Removing also apostrophes ( ' ) from $(this) inside filter function :
Replacing :
return $('this').attr('lvl')> lvl;
By :
return $(this).attr('lvl') > lvl;
And it work, Hope that this help.
you can use turnery operator here:
Like
return $('this').attr('lvl')> lvl ? lvl : $('this').attr('lvl');
I'm using ng-repeat with a limitTo filter and a button to raise the limit when clicked. Is there any way to check if the next item in the ng-repeat iteration exists/count how many more items there are so that i can hide the 'load more' button/show how many more items there are.
below is sort of an example of what I am trying to do:
<div ng-repeat="comment in collection.data | limitTo:commentLimit">
{{comment.text}}
<div ng-show="filteredItems[$index + 1]" ng-click="increaseLimit()">load more (3 more replies)</div>
</div>
You can do something similar to this codepen:
http://codepen.io/anon/pen/waxOZL
<div ng-repeat="comment in collection.data | limitTo:commentLimit">
{{comment.text}}
</div>
<div ng-show="collection.data.length > commentLimit" ng-click="increaseLimit()">load more (3 more replies)</div>
Also, you should put the load more link outside the ng-repeat to show it only once.
Ideally, I think what you want to do is set an increment value in your scope, and add a new function called nextIncrementAmount which will help you display the number of new replies the button will add when clicked.
$scope.commentLimit = 3;
$scope.incrementStep = 3;
//use this function to increase the filter limit
$scope.increaseLimit = function() {
var newLimit = $scope.commentLimit + $scope.incrementStep;
$scope.commentLimit = (newLimit < $scope.collection.data.length) ? newLimit : $scope.collection.data.length;
}
//use this function to show the number of replies the increment button will increment by.
$scope.nextIncrementAmount = function() {
var newLimit = $scope.commentLimit + $scope.incrementStep;
return (newLimit < $scope.collection.data.length) ? $scope.incrementStep : $scope.collection.data.length - $scope.commentLimit;
}
Then in your view you'll want to do something like this:
<div ng-repeat="comment in collection.data | limitTo:commentLimit">
{{comment.text}}
</div>
<div ng-if="collection.data.length != commentLimit"
ng-click="increaseLimit()">
load more (<ng-pluralize count="nextIncrementAmount()"
when="{
'1': '{} more reply',
'other': '{} more replies',
}"> </ng-pluralize>)
</div>