I'm using jQuery's append() and the forEach() function to map through an array of objects, displaying the data to a slideshow. Although the array has one object in it, the resulting markup has extra data, essentially the append() method is appending the same markup 2x or more times.
I've tried to remove the markup and instead replace it with "Hello World" (no tags) and it renders correctly. However, when I input "Hello World", it will be appending 3 times as opposed to once. I've console.logged the array to ensure that it only contains one object before and during the forEach() method and can confirm that there is only one element in the array, therefore this is an issue with append()
$.getJSON(
`${window.location.origin}/public/js/config/shopCards.json`,
function(res) {
var featuredItems = res.filter(function(item) {
return item.isFeatured;
});
if (featuredItems.length === 0) {
$('.featured-items').empty();
return;
}
console.log(featuredItems, featuredItems);
featuredItems.forEach(function(item) {
console.log(item);
$('.siema-home').append(`
<div class="card card-shop home-card ${
item.isExclusive ? 'exclusive' : ''
} ${item.isOnSale ? 'sale' : ''} ${item.isFeatured ? 'featured' : ''} ${item.isSemiExclusive ? 'semiExclusive' : ''}" data-id=${item.id}>
<div style="position: relative">
<img src=${
item.thumbnailURL
} class="card-img-top" alt=${item.projectName} draggable="false"/>
<div class="card-more-details">
<p class="helper-text">Click For More Details</p>
${
item.isExclusive
? '<span class="badge badge-warning mb-2">Exclusive Build</span>'
: ''
}
${
item.isSemiExclusive
? '<span class="badge badge-danger mb-2">Semi-Exclusive Build</span>'
: ''
}
${
item.isOnSale
? '<span class="badge badge-success mb-2">On Sale</span>'
: ''
}
${
item.isFeatured
? '<span class="badge badge-info mb-2">Featured</span>'
: ''
}
</div>
</div>
<div class="card-body card-shop-body">
<div>
<h5 class="card-title-shop text-center">
${item.projectName}
</h5>
<p class="card-price text-center">$${item.price}</p>
</div>
</div>
</div>`);
});
I expect to only see one "shop-card" in the slider.
The actual output is 3 cards in the slider.
Debug information: Chrome w/ Dev console
Full index.html available here (for further scrutiny)
So after tedious work and testing, I found out that the issue was actually with the slider, Siema, which actually duplicates the markup and adds it back into the siema-home div. Another issue was with using width: 100% with Siema, which causes the slider to break and display the extra-slides it created side-by-side with the markup appended by the append() function.
TLDR: This was an issue with the slider and the fix was to edit the width from 100% to a smaller value or used a definite pixel value.
Related
I have a problem, I got an HTML element that acts like a loding spinner, and I would like it not to be displayed. I would to use the observables to be able to load that element only once the data is fully loaded. So far, in my component, i made it like that :
const matchTableList$ = this.matchTablesService.list().pipe(
map(matchTables => {
matchTables = matchTables.sort((a, b) => a.name.toLocaleLowerCase() === b.name.toLocaleLowerCase() ? 0 : a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase() ? -1 : 1);
this.matchTables$.next(matchTables);
}),
catchError( (error: HttpErrorResponse) => {
this.loadingError$.next(true);
return EMPTY;
}),
finalize(() => {
this.prettyMessageData = new PrettyMessageContent();
this.prettyMessageData.title = "hello"
this.prettyMessageData.message = " ";
this.prettyMessageData.withMessage(this.prettyMessageData.message);
})
);
and in my HTML i made :
<div *ngIf="!matchTablesLine" class="justify-content-center">
<pretty-message style="width: 100%;" [data]="prettyMessageData">
</pretty-message>
<div class="d-flex justify-content-center mt-5">
<button class="btn--primary" (click)="createMatchTable()"><i class="add-circle-line"></i>add</button>
</div>
</div>
So the problem here is that, when there is no data, the pretty message is not displayed, and when there is data, the html div is loaded before i got the data, so it's weird to see a button while the page load. I think it is possible to use observables and operators here, but i really don't know which one to use to make this work. Thanks.
Edit : I solved the problem using a simple resolver, which is really helpful in that kind of cases.
I believe you are trying to delay the rendering of the button while the prettyMessageData is undefined. You can achieve this by adding a *ngIf=prettyMessageData on the button div.
<div *ngIf="prettyMessageData" class="d-flex justify-content-center mt-5">
<button class="btn--primary" (click)="createMatchTable()"><i class="add-circle-line"></i>add</button>
</div>
I have a div which I have set to align="right". I have created a local variable called userId and assigned 1 to it and I am wondering if is possible to somehow set the div to left align if userId === 1, which will be the case. I've tried reading the react docs on conditional rendering but I don' believe that is what I'm looking for as they all deal with rendering whereas the div that I want to align is being returned by an export function so the render function isn't used.
export function MessageRow({ message, fetch }) {
return (
<div>
<br />
<div align="right" className="Message-Body">
<div className="Message-row-header">{message.user}</div>
<div>{message.content}</div>
<div className="muted-text">
(Sent: {new Date(message.timestamp).toUTCString()})
</div>
<div>
<button
className="block"
onClick={() => messageService.delete(message.id).then(fetch)}
>
Delete
</button>
<button className="block">Edit</button>
</div>
</div>
</div>
);
}
This is what I currently have and was thinking of trying a function like below but I am unsure how I would then get it to apply to the div.
function checkMessageUserID(userId) {
if (userId === 1) {
}
}
It is still being used from a render() point of view though, no?
So you could still do what you want:
return (
<div><br />
{userId !== 1 ?
<div align="right" className="Message-Body">
:
<div align="left" className="Message-Body">
}
...
1) You can return JSX from the function and call the function inside return.
function checkMessageUserID(userId) {
if (userId === 1) {
<div align="right" className="Message-Body">
}
else{
<div align="left" className="Message-Body">
}
}
Then inside return call {checkMessageUserID()}
2) You can also use ternary operator inside your render.
<div align = {userID == 1 ? "right" : "left"} className="Message-Body">
Conditional rendering works the same for functional as well as stateful components.
Working code snippet below.
<div align={userId === 1 ? 'left' : 'right' } className="Message-Body">
You could do any of the above, or what I would recommend is, you create two styling classnames, you can call them 'left/right-message' or 'mine/otherPerson-message' and you can assign align: 'left/right' to each, you can even assign different colors for that chat feel, you'd achieve this simply by doing:
<div className={userId === 1 ? "left-message" : "right-message" >
...
</div>
This is not a duplicate.
In the other post, they are just doing a ternary operation. I wanna changes classes within ng-repeat.
I have this piece of code with little bugs.
HTML:
<div id="server-id-list-container" class="panel-body col-md-12 scrollbar">
<div class="server-id-list-element" ng-class="serverIdLength > 12 ? 'col-md-3' : 'col-md-2'" ng-repeat="server in selection.serverIds">
<p class="alert alert-info">{{server.serverId}}<span ng-click="removeServerId($index)" class="glyphicon glyphicon-remove"></span></p>
</div>
</div>
Controller:
_.forEach($scope.selection.serverIds, function(a) {
$scope.serverIdLength = a.serverId.length;
});
Scope Object:
[
{
"serverId": "loma1pwipdb2002",
"serverName": "",
},
{
"serverId": "shdmqprtp1",
"serverName": "",
}
]
When I enter "loma1pwipdb2002", the class becomes col-md-3 and since I am using ng-repeat applies for all elements. I want the class to be applied only to serverIdLength > 12 and if its lesser than 12, col-md-2 should get applied.
Please advice.
Is it correct that you want to switch your class for each element of selection.serverIds list separately based on serverId string length? Need to know your selection.serverIds, is it your "Scope Object"? If yes, then I would do just
<div
class="server-id-list-element"
ng-repeat="server in selection.serverIds"
ng-class="server.serverId.length > 12 ? 'col-md-3' : 'col-md-2'"> ... </div>
The problem is that your $scope.serverIdLength is being calculated once for all the list. While you want to have a dynamic class based on each item specific property.
Let's continue discussion if I didn't understand the issue and the entry conditions.
the issue seems to lie here:
_.forEach($scope.selection.serverIds, function(a) {
$scope.serverIdLength = a.serverId.length;
});
No matter what $scope.serverIdLength will always be set to the length of the last serverId. That because it's a global variable and there is only one instance of it. This is why all your classes match. They all reference the same variable.
Instead like #dhilt suggested ditch the controller code and acccess the length in the dom:
ng-class="server.serverId.length > 12 ? 'col-md-3' : 'col-md-2'"
Try that:
ng-class="{'col-md-3':server.serverId.length > 12, 'col-md-2':server.serverId.length <= 12}"
Iam not getting slick carousel with updated data when i update this ng-repeat data of slider from my controller.
<slick lazyLoad=ondemand init-onload=true slides-to-show=5 slides-to-scroll=1 next-arrow=".rightOne" prev-arrow=".leftOne" data="trailersUpcomming">
<div index="$index " ng-repeat="trailer in trailersUpcomming ">
<div class=" boxhover testimonialslider" style="margin-right: 12px; ">
<div class="card " style="border-color: green; ">
<div style="padding: 17px;text-align: left;height: 124px;background-color: #ffffff;">
<div>ReleaseDate : {{trailer.releasedate}}</div>
<div>Language : {{trailer.filmlanguage}}</div>
<div>Rating : {{trailer.filmrating}}</div>
</div>
</div>
</div>
</div>
</slick>
Try to update your array scope by using angular.copy
for reference please refer this example angular slick update example
The place there you are updating your data just use
$timeout(function(){
//update your variable here.
}
I had faced similar issue. Using angular's old version i.e. 1.4 and using slider carousel. On refresh/page reload carousel was not getting refreshed with latest data.
$('.slider').slick('reinit'); or $('.slider').slick('refresh');
did not work me so I had to play with data coming from server into angular client.
Did fix that with no so great solution but it worked for me.
What I observed is that, the array which is used to iterate and display elements in it on the carousel do not work if its reference changes on page reload. If you directly do not assign data array to the target array whose elements are being shown on Carousel then it works.
For that, I am using array's Push() method
for (let i=0; i < data.length ; i++) {
var id = vm.targetArray.length + 1;
if ( vm.targetArray.filter(item=> item.name == data[i].name).length == 0){
vm.targetArray.push(data[i]);
console.log("Pushed the item to targetArray : " + data[i].name);
}
}
I am constructing Jquery elements dynamically and i have used .clone() and .html() and .append() alot in my code. this works fine with chrome and firefox even IE9. But IE8 Its creating element with attribute sizeset and sizechar. My Jquery version is 1.7. I know there alot around 4 to 5 Issue raised in Stackoverflow on same topic, but i havent found even one answer useful . Please help me with this as it's blocking my complete work. i cant user removeAttr as , its sizcache08213372050765756 some random junk value. and if i use regEx
var re = /\s*(sizset|sizcache)\d*="[^"]*"/gi;
source = source.replace(re,'');
mentioned in one of the thread
How to get rid of sizset and sizcache attributes from jQuery?
then return value is "no", i dono how.
IE8 Contruction
<DIV class=findings sizcache08213372050765756="38" sizset="54">
<DIV id=fnd-cv1 class="finding finding-readonly fnds-O closed" sizcache08213372050765756="38" sizset="54">
<DIV class="cap-fnd-summary finding-summary summary clearfix" sizcache08213372050765756="36" sizset="0">
<SPAN class=line-item>MS-2.3</SPAN>
<A class=finding-title href="" jQuery17034048751834028246="188" toggleview="closed" sizcache08213372050765756="36" sizset="1"><SPAN class=icon-text-toggle></SPAN>Fnd 10</A><SPAN class="status finding-status">Open</SPAN> <SPAN class="status finding-status-item PA" href="">PA</SPAN> <SPAN class="status finding-status-item CA" href="">CA</SPAN> <SPAN class="status finding-status-item ROOT" href="">ROOT</SPAN>
</DIV>
<DIV class="finding-items clearfix" sizcache08213372050765756="38" sizset="54"><SPAN class=recidivism sizcache08213372050765756="36" sizset="9"></DIV>
</DIV>
</SPAN>
</DIV>
Don't use regex to parse HTML, iterate over elements and attributes, and remove them if they match a condition.
I whipped together a jQuery plugin that should work
$.fn.sizRemove = function() {
return this.each(function() {
for (var i=this.attributes.length; i--;) {
var n = this.attributes[i].nodeName;
if (n.indexOf('sizset') === 0 || n.indexOf('sizcache') === 0)
this.removeAttribute(n);
}
});
};
to be called like
$('#fnd-cv1').sizRemove();
// or for all elements
$('*').sizRemove();
FIDDLE