I am working on a site that need to have certain words changed. The problem is the HTML etc is not controlled by myself. e.g. I can not edit the html. However, I can append extra code to the end.
The code I need to change is the wording "CHANGE ME" in:
<div class="price">
<a class="button" ng-click="commands.order.execute()"
ng-class="(!session.hidePrice && project.project.requiredCalculation) ? 'refreshing' : ''">
<span class="icon mdi mdi-cart" ng-class="::$root.icons.basket"></span>
<currency value="project.project.total.total"
class="price-total ng-isolate-scope ng-hide"
ng-show="!session.hidePrice && project.project.pricing">
<span class="currency ng-binding">
<span ng-class="left" class="ng-binding currency-sign-left">£</span>
1,089.02<span ng-class="right" class="ng-binding ng-hide">£</span>
</span>
</currency>
<span ng-show="session.hidePrice || !project.project.pricing" class="ng-binding">
CHANGE ME
</span>
</a>
</div>
I can change the whole class using:
<script type="text/javascript">
var myClasses = document.getElementsByClassName("price");
for (var i = 0; i < myClasses.length; i++) {
myClasses[i].innerHTML = "new content";
}
</script>
Problem is, this removes all the coding and replaces with "new content". What I need to do is keep the content the same but replace the wording "CHANGE ME" with something else.
p.s. ideally I want to say something like Change the wording "CHANGE ME" if it is in the class "price" and the class="ng-binding" (or another identifier, don't know if you can use "ng-show" to identify??)
If possible, please include a fiddle
p.s. needs to be onload so no buttons etc (so no user input needed)
If you cannot change the Angular code, you can use a selector.
div.price > a.button span:nth-child(3)
document.querySelector('div.price > a.button span:nth-child(3)').innerHTML = 'Hello World!';
<div class="price">
<a class="button" ng-click="commands.order.execute()" ng-class="(!session.hidePrice && project.project.requiredCalculation) ? 'refreshing' : ''">
<span class="icon mdi mdi-cart" ng-class="::$root.icons.basket"></span>
<currency value="project.project.total.total" class="price-total ng-isolate-scope ng-hide" ng-show="!session.hidePrice && project.project.pricing">
<span class="currency ng-binding">
<span ng-class="left" class="ng-binding currency-sign-left">£</span>
1,089.02
<span ng-class="right" class="ng-binding ng-hide">£</span>
</span>
</currency>
<span ng-show="session.hidePrice || !project.project.pricing" class="ng-binding">
CHANGE ME
</span>
</a>
</div>
You can write a function to loop over all matching elements and either replace some or all of the content.
setContent('div.price > a.button > span', 'CHANGE ME', 'Hello World!', false);
function setContent(selector, pattern, text, replaceContent) {
var els = document.querySelectorAll(selector);
for (var i = 0; i < els.length; i++) {
var el = els[i];
if (replaceContent) {
el.innerHTML = el.innerHTML.replace(pattern, text);
} else {
if ((pattern instanceof RegExp && el.innerHTML.match(pattern)) ||
(typeof pattern === 'string' && el.innerHTML.trim() === pattern)) {
el.innerHTML = text;
}
}
}
}
<div class="price">
<a class="button" ng-click="commands.order.execute()" ng-class="(!session.hidePrice && project.project.requiredCalculation) ? 'refreshing' : ''">
<span class="icon mdi mdi-cart" ng-class="::$root.icons.basket"></span>
<currency value="project.project.total.total" class="price-total ng-isolate-scope ng-hide" ng-show="!session.hidePrice && project.project.pricing">
<span class="currency ng-binding">
<span ng-class="left" class="ng-binding currency-sign-left">£</span>
1,089.02
<span ng-class="right" class="ng-binding ng-hide">£</span>
</span>
</currency>
<span ng-show="session.hidePrice || !project.project.pricing" class="ng-binding">
CHANGE ME
</span>
</a>
</div>
If the purpose is to only look at text content, then you should iterate over all the text nodes and apply a test/replace on each of those. You can use createTreeWalker to iterate over such nodes:
function textNodesUnder(el){
var n, a=[], walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false);
while(n=walk.nextNode()) a.push(n);
return a;
}
textNodesUnder(document.querySelector('.price')).forEach(function(node) {
node.data = node.data.replace('CHANGE ME', 'new Content');
});
<div class="price">
<a class="button" ng-click="commands.order.execute()" ng-class="(!session.hidePrice && project.project.requiredCalculation) ? 'refreshing' : ''">
<span class="icon mdi mdi-cart" ng-class="::$root.icons.basket"></span>
<currency value="project.project.total.total" class="price-total ng-isolate-scope ng-hide" ng-show="!session.hidePrice && project.project.pricing"><span class="currency ng-binding"><span ng-class="left" class="ng-binding currency-sign-left">£</span>1,089.02<span ng-class="right" class="ng-binding ng-hide">£</span></span></currency>
<span ng-show="session.hidePrice || !project.project.pricing" class="ng-binding">
CHANGE ME
</span>
</a>
</div>
Vanilla possible solution:
To replace a string you can use String.prototype.replace().
If you need instead to append some text in innerHTML you can use +- (JavaScript Assignment Operator) which will append your new content in the current content visible in innerHTML;
myClasses[i].innerHTML += "new content";
Generic example using Assignment Operator:
let result = document.getElementById('result');
document.getElementById('button').addEventListener('click', event => {
result.innerHTML += 'new content</br>';
});
<button id="button">Click me!</button>
<div id="result">Hello some content here!</br></div>
why not using angularjs with ng-bind:
<span ng-show="session.hidePrice || !project.project.pricing"
ng-bind="(session.hidePrice || !project.project.pricing) ? 'CHANGE ME' : 'new Content'"
class="ng-binding">
</span>
Using a directive:
app.directive('price', function(){
return {
restrict:'C',
link:function(scope, el, attrs){
angular.element(el).find('span').last().html('new Content');
}
};
})
Related
I just encounter a problem I have written a directive but its not getting update, I dont know why, in console it does change but in directive it does not.
Here is my directive
mainControllers.directive('mallsproduct', function () {
return {
restrict: 'E',
scope: {
productInfo: '=info',
linkid: '=linkid'
},
templateUrl: 'directives/dashboard_product.html'
};
});
Here is my `html`
<div class="aa-properties-content-body mg-7" ng-controller="DashboardController as ctrl">
<ul class="aa-properties-nav aa-list-view">
<li style="border: 1px solid #ccc;margin-bottom: 25px;" ng-repeat="active_products in productInfo.items">
<article class="aa-properties-item mg-top-0-notimp">
<a class="aa-properties-item-img" href="#/product/{{active_products.id}}">
<img ng-if="active_products.photos[0].path" resize-image alt="img" class="" src="{{active_products.photos[0].path}}">
<img ng-if="!active_products.photos[0].path" resize-image class="" src="img/default_product.jpg" alt="">
</a>
<div class="aa-properties-item-content">
<div class="aa-properties-about padding-0-notimp">
<h5>{{active_products.name| limitTo : 10}}{{active_products.name.length > 10 ? '...' : ''}}</h5>
<p class="font-size-11-imp"><i class="fa fa-building-o" aria-hidden="true"></i> {{active_products.mall.name| limitTo : 10}}{{active_products.mall.name.length > 10 ? '...' : ''}}</p>
<p class="font-size-11-imp"><i class="fa fa-map-marker" aria-hidden="true"></i> {{active_products.mall.address| limitTo : 10}}{{active_products.mall.address.length > 10 ? '...' : ''}}</p>
<p class="font-size-11-imp"><i class="fa fa-phone" aria-hidden="true"></i> {{active_products.shop.telephone}}</p>
<p class="font-size-11-imp" ng-if="linkid == 3"><i class="fa fa-eye" aria-hidden="true"></i> {{active_products.views}}</p>
<div class="modal-demo">
<script type="text/ng-template" id="myModalContent.html">
<div ng-include src="'partials/update_product.html'"></div>
</script>
<div ng-controller="AddProductController">
<button ng-click="view_product(active_products.id)"><i class="fa fa-pencil" aria-hidden="true"></i></button>
<button ng-click="del_product(active_products.id)"><i class="fa fa-trash-o" aria-hidden="true"></i></button>
<button ng-if="linkid == 2" ng-init="status = 1" ng-click="reactivate_product(active_products.id, status)"><i class="fa fa-lock" aria-hidden="true"></i></button>
</div>
<div class="modal-parent">
</div>
</div>
</div>
</div>
</article>
</li>
</ul>
<div class="aa-title pad-top-30" ng-if="linkid == 1">
<p>Global page count for active product is {{global_pagecount}} and active product count from API is {{productInfo._meta.pageCount}}</p>
<h3 ng-if="global_pagecount < productInfo._meta.pageCount" class="text-align-center color-feroz cursor-pointer" ng-click="load_more(global_pagecount, linkid)">{{$root.translated_labels.dashboard.load_more}}</h3>
</div>
<div class="aa-title pad-top-30" ng-if="linkid == 3">
<p>Global page count for most viewed is {{global_pagecount_mostv}} and most viewed count from API is {{productInfo._meta.pageCount}}</p>
<h3 ng-if="global_pagecount_mostv < productInfo._meta.pageCount" class="text-align-center color-feroz cursor-pointer" ng-click="load_more(global_pagecount_mostv, linkid)">{{$root.translated_labels.dashboard.load_more}}</h3>
</div>
</div>
I am including directive in dashboard partial like this
<div class="active tab-pane" ng-if="linkid === '1'">
<malls-product info="active_products" linkid="linkid"></malls-product>
</div>
<!--Active products list ends here -->
<!-- Get Inactive Products -->
<div class="active tab-pane" ng-if="linkid === '2'" >
<malls-product info="$root.inactive_products" linkid="linkid"></malls-product>
</div>
<!--Get Inactive products ends here -->
<div class="active tab-pane" ng-if="linkid === '3'" >
<malls-product info="$root.mostviewed_products" linkid="linkid"></malls-product>
</div>
<!-- View Profile-->
and This is the api which does show the result in console.
$scope.global_pagecount = 1;
$scope.active_product = function () {
$http.get($rootScope.baseurl + 'abc?&page=' + $scope.global_pagecount,
{headers:
{'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': $rootScope.keyword_auth_token, 'Accept-Language': $cookies.get('type')}
})
.success(function (data) {
//$scope.active_product_pageCount = data._meta.pageCount;
if ($scope.global_pagecount === 1) //I know for sure the first page of pagination is 1
{
$scope.active_products = data;
}
if ($scope.global_pagecount > 1) // If user click load more global count gets incremented and new results push in active_producst
{
/* for loading new results Pagination Applied */
for (var times = data.items.length - 1; times >= 0; times--) {
$scope.active_products.items.push(data.items[times]);
}
}
console.log($scope.active_products);
})
.error(function (data) {
// console.log(data);
});
};
What is the issue, why it is not getting update, If I use rootscopethen it works fine, obviously it has too, but not with $scope.
Note : when scope.global_pagecount value is equal to 2 i get new results but not in directive only in console. By default scope.global_pagecount has value equal to 1.
You don't use your directive correctly. You define it as:
mainControllers.directive('mallsproduct'
Which means you should use it as:
<mallsproduct ..>
Or define your directive camelcased:
mainControllers.directive('mallsProduct'
Then you can use it as you do now:
<malls-product ..>
This is because of the Isolated scope doesn’t know anything about its parent scope. You just created a directive with an isolated scope.
To access any parent scope data, we need to pass the scope data to our directive explicitly. This is achieved by setting properties on the scope object in the DDO.
Another important thing is that, these properties also MUST be set as the attributes of the directive html element.
How would I select a certain element in this drop down list.
<li role="presentation" ng-repeat="match in $matches" ng-class="{active: $isActive($index)}" class="ng-scope active">
<a style="cursor: default" role="menuitem" tabindex="-1" ng-click="$select($index, $event)">
<!-- ngIf: $isMultiple && $isActive($index) -->
<i class="glyphicon glyphicon-ok pull-right" ng-if="$isMultiple && $isActive($index)"></i>
<!-- end ngIf: $isMultiple && $isActive($index) -->
<span ng-bind="match.label" class="ng-binding">Streamer</span>
</a>
</li>
I tried this
element(by.model('selectedAvailable')).click();
element(by.xpath('..//ul//li[1]')).click().
and this:
element(by.repeater('match in $matches').row(0)).click();
An alternative would be to use by.cssContainingText :
element(by.cssContainingText('[ng-repeat="match in $matches"]', 'Streamer')).click();
I would filter() it, assuming you know the "Streamer" label and want to select it:
var matches = element.all(by.repeater('match in $matches'));
matches.filter(function (match) {
return match.element(by.binding("match.label")).getText().then(function (text) {
return text === "Streamer";
});
}).first().click();
Or, in a similar fashion with evaluate() instead of getText():
var matches = element(by.repeater('match in $matches'));
matches.filter(function (match) {
return match.evaluate("match.label").then(function (label) {
return label === "Streamer";
});
}).first().click();
<div class="full-row" ng-repeat="row in pendingRequests | orderBy: '-modificationDate' | partition:3">
<div class="one-third" ng-repeat="request in row track by request.id">
<div class="incoming_request" ng-class="actionClass(request)">
<div class="request_comments">
<hr>
<p><span>Recipients:</span></p>
<div class="comments">
<p ng-repeat="comment in request.comments track by comment.id" class="dont-break-out">
<span class="author" ng-bind="comment.userName | employeeName">:</span>
{{comment.text}}
<span ng-if="comment.status == State.APPROVED" class="approval success" ng-click="changestatus(comment, request)"><i class="fa fa-check"></i></span>
<span ng-if="comment.status == State.REJECTED" class="approval error" ng-click="changestatus(comment, request)"><i class="fa fa-times"></i></span>
<span ng-if="comment.status == State.PENDING" class="approval" ng-click="changestatus(comment, request)" title="{{showApproveTooltip(comment)?'Click to approve the request on behalf of this user':''}}"><i class="fa fa-clock-o"></i></span>
</p>
</div>
</div>
<div class="request_resolve">
<hr>
<div class="textarea-holder">
<textarea placeholder="Your comment..." ng-model="request.newComment" ng-model-options="{ updateOn: 'default blur'}"></textarea>
</div>
<div class="button-container">
<button ng-click="approve(request);" ng-disabled="request.isProcessing" class="btn btn-primary" am-hide-request-resolve-div>Confirm<i ng-hide="request.isProcessing" class="fa fa-check"></i><span ng-show="request.isProcessing" class="spinner no-hover"><a><i class="fa-li fa fa-spinner fa-spin"></i></a></span></button>
<button ng-click="reject(request);" ng-disabled="request.isProcessing" class="btn btn-default pull-right" am-hide-request-resolve-div>Reject <i class="fa fa-times"></i></button>
</div>
</div>
Here is peace of code. As You may see there are many ng-repeats. My pendingRequests collection very often is updated from server. After 3 or more updates when I click on some button nothing is happend on UI.
Details :
On approve click I change status of one comment.
$scope.approve = function (request) {
var currentUserComment = request.comments.filter(function(comm) {
return comm.userId == user.id && comm.status == "Pending";
})[0];
currentUserComment.status = State.APPROVED; // change comments Status
currentUserComment.text = request.newComment;
delete request.newComment;
if (!currentUserComment) {
request.isProcessing = false;
return;
}
Comments.update(currentUserComment, function() {
// $rootScope.$broadcast('daysUpdated');
});
request.isProcessing = false;
};
This must show this span <span ng-if="comment.status == State.APPROVED" class="approval success" ng-click="changestatus(comment, request)"><i class="fa fa-check"></i></span> , cause now status is equal to State.APPROVED. But nothing happens.
After some research I think it all because ng-repeat and collection updates.
ng-repeat creates a child scope for each item, and so the scopes in play might look like this:
bookCtrl scope = { tags: [ 'foo', 'bar', 'baz' ] }
ng-repeat child scopes: { tag: 'foo' }, { tag: 'bar' }, { tag: 'baz' }
So when I update comment.status for some request Angular don't know in what scope it exists.
Am I right? And how can I solve my problem (after changing comment status show correct span)?
More Simple code :
<div ng-repeat="request in requests">
<div ng-repeat="comment in request.comments">
<span ng-if="comment.status == State.APPROVED" class="approval success"><i class="fa fa-check"></i></span>
<span ng-if="comment.status == State.REJECTED" class="approval error"><i class="fa fa-times"></i></span>
<span ng-if="comment.status == State.PENDING" class="approval"><i class="fa fa-clock-o"></i></span>
</div>
<div>
<button ng-click="approve(request)">
Approve
</button>
</div>
</div>
And approve function :
var user = LoggeInUser(); // some user who is loggedIn now
$scope.approve = function(request){
var currentUserComment = request.comments.filter(function(comm) {
return comm.userId == user.id && comm.status == "Pending";
})[0];
currentUserComment.status = State.APPROVED; // change comments Status
Comments.update(currentUserComment, function() { // send PUT request to API
// $rootScope.$broadcast('daysUpdated');
});
}
You may find your solution in moving the functions to $scope.functions.functionName. I believe from reviewing this that you are running into scoping issues, as you alluded to in your statement.
JS
$scope.functions.approve = function () { ... }
HTML
functions.approve(request)
You also might have a look at using controller as, sometimes that can help:
https://docs.angularjs.org/api/ng/directive/ngController
Attempting with the below jQuery method: But this does not work in my Angular environment, assuming because I'm attempting to do this outside of angular JS scope methods, but I don't know how to implement this using Angular scope methods (new to angular) any advice?
$('.song-thumb .hover-play').on('mouseenter', function(e) {
var elem = $('section.suggestedAlbums img');
elem.trigger(e.type);
elem.addClass('hoverclass');
});
$('.song-thumb .hover-play').on('mouseleave', function(e) {
var elem = $('section.suggestedAlbums img');
elem.trigger(e.type);
elem.removeClass('hoverclass');
});
var count = 0;
$('section.suggestedAlbums img').hover(function() {
count++;
$('[remove]').html('<label remove><br>It triggers the hover event(' + count + ') too.<br></label>');
});
Full page code:
<script>
$('.song-thumb .hover-play').on('mouseenter', function(e) {
var elem = $('section.suggestedAlbums img');
elem.trigger(e.type);
elem.addClass('hoverclass');
});
$('.song-thumb .hover-play').on('mouseleave', function(e) {
var elem = $('section.suggestedAlbums img');
elem.trigger(e.type);
elem.removeClass('hoverclass');
});
var count = 0;
$('section.suggestedAlbums img').hover(function() {
count++;
$('[remove]').html('<label remove><br>It triggers the hover event(' + count + ') too.<br></label>');
});
</script>
<!-- <h2>{{trackListData.listTitle}}</h2>
--><div ng-repeat="track in trackListData.tracks track by $index " class="feature-item-homepage fade-animate-nostagger">
<div class="song-thumb" ng-class="{active: $root.currentPlaying.song_id == track.id}">
<!--3 Cases-->
<!--Not the song being played-->
<div class="hover-play" ng-if="$root.currentPlaying.song_id != track.id" ng-click="$root.playSong(track);">
<i class="fa fa-plus add-to-playlist" ng-init="playlistOption = false" ng-click="$root.initPlaylistOption($event, track.id); $event.stopPropagation();"></i>
<i class="fa fa-play play-song"></i>
<img src="img/producer_icon_white.png" class="prod_logo">
<div class="song-title" style="width: 80%;padding-top:25px;">
<a class="song-linking" href="#/song/{{track.id}}">
<h4>{{track.title}}</h4>
<h5>{{track.artist.user_name}}</h5>
</a>
</div>
</div>
<!--The current song but paused-->
<div class="hover-play" ng-if="$root.currentPlaying.song_id == track.id && !$root.isPlaying" play-music>
<i class="fa fa-plus add-to-playlist" ng-init="playlistOption = false" ng-click="$root.initPlaylistOption($event, track.id); $event.stopPropagation();"></i>
<i class="fa fa-play play-song"></i>
</div>
<!--The current song but playing-->
<div class="hover-play" ng-if="$root.currentPlaying.song_id == track.id && $root.isPlaying" pause-music>
<i class="fa fa-plus add-to-playlist" ng-init="playlistOption = false" ng-click="$root.initPlaylistOption($event, track.id); $event.stopPropagation();"></i>
<i class="fa fa-pause pause-song"></i>
</div>
<img ng-src="{{(track.albums[0].album_picture? $root.fileServer +'uploads/' + track.albums[0].album_picture:(track.artist.profile_picture? $root.fileServer +'uploads/' + track.artist.profile_picture:'img/defaultalbum.png'))}}" />
</div>
<!-- <div class="song-title-wrap">
<div class="song-title">
<a class="song-linking" href="#/song/{{track.id}}">
<h4>{{track.title}}</h4>
<h5>{{track.artist.user_name}}</h5>
</a>
</div>
</div> -->
</div>
Add a controller to a containing div:
<div ng-controller='MyController'>
Add ngMouseleave and ngMouseenter to the .song-thumb .hover-play element
<div class="hover-play" ng-if="$root.currentPlaying.song_id != track.id" ng-click="$root.playSong(track);" ng-mouseenter='state.hoverPlay=true;' ng-mouseleave='state.hoverPlay=false'>
Add the controller
angular.controller('MyController', [ '$scope', function ($scope) {
$scope.state = {
hoverPlay: false
};
}]);
Use ngClass to add/remove the class
<img ng-class="{ 'hoverclass': state.hoverPlay }" . . . >
I have a jQuery code that looks for a specific div element.
If the element exist I define a variable and use parseFloat() function. Since there are going to be more than one element with the same class I've created an array.
So far I've managed to hide the element called: div.ifc-balance-div; however I am not quite sure how I can hide the div.ribbon-yellow, in case the element does not have the variable savePrice.
(function($) {
"use strict";
$(document).ready(function() {
var j = 0,
savePrices = jQuery('.special-price .price .price').map(function() {
return parseFloat(jQuery(this).text().replace(/[^0-9\.]+/g, ""), 10);
}).get();
if(j < savePrices.length){
++j;
}
for (var i = 0; i < savePrices.length; ++i) {
if (Number(savePrices[i]) > 0) {
var ifcBalance = Number(savePrices[i]) / 1,
m = parseFloat(ifcBalance).toFixed(0);
$('div.ifc-balance-div' + (i + 1)).html('<p class="dynamic-badge-txt"><b>£' + m + ' OFF</b></p>');
$('div.ribbon-yellow').html('<div class="badge-ends-message">ENDS TUESDAY</div>');
}
else {
$('div.ifc-balance-div' + (i + 1)).hide();
}
}
});
})(jQuery);
Here is a sample of the HTML Code:
one having Save Price:
Text
<div class="price-box">
<p class="old-price">
<span class="price-label">Was</span>
<span class="price" id="old-price-15510">
<span class="price"><span class="currency">£</span>599</span> </span>
</p>
<p class="special-price">
<span class="price-label">You Save</span>
<span class="price" id="price-excluding-tax-15510">
<span class="price"><span class="currency">£</span>300</span> </span>
</p>
</div>
From
£299
One without save price:
<div class="ribbon-yellow"></div>
<div>
</div></div></div>
<a href="#" title="#">
<img src="#" alt="#">
</a>
</div>
<div class="item__detail">
<a href="#" title="#" class="item__link">
<p class="product-name item__name">Text</p>
</a>
<div class="price-range">
<span class="price-label">From </span>
<span class="price"><span class="price"><span class="currency">£</span>299</span></span>
</div>
</div>
</div>