I have a dating project. We are using laravel 6 and jquery 3.4.1
The problem is that I need to draw a div when receiving AJAX.
So, javascript and blade template :
static countNewMessages() {
$.get('/some/link/here', results => {
let total = 0;
if (results.length === 0) {
$('.chat__list-block').each(function (index) {
$(this).removeClass('chat__list-block_new');
});
$('.chat__list-non-read-counter').addClass('chat__list-non-read-counter_hidden').each(function (index) {
$(this).text('');
});
$('#number-of-new-messages').addClass('d-none').removeClass('d-flex').html('');
$('#inbox-messages-count-title').html('0');
return false;
}
results.forEach(v => {
if (Chat.containers?.threads) {
let threadElement = $('.chat__list-block[data-pid=' + v.from_userid + ']');
threadElement.addClass('chat__list-block_new');
threadElement.find('.chat__list-non-read-counter')
.addClass('chat__list-non-read-counter_hidden')
.text(v.count);
if (0 < threadElement.length && !threadElement.hasClass('chat__list-block_active') && 0 < v.count) {
threadElement.find('.chat__list-non-read-counter')
.removeClass('chat__list-non-read-counter_hidden');
}
}
total += v.count;
$('#number-of-new-messages').addClass('d-flex').removeClass('d-none').html(total);
$('#inbox-messages-count-title').html(total);
});
});
}
#if(count($threads))
<div>Chat requests</div>
#else
<div>No chat requests</div>
#endif
The standard if-else behavior in the template suits me fine. If a user visits the page but has no messages the second block is displayed, and if he has messages the first block is displayed. But if a user who is on the block "no chat requests" and receives new messages then the block "chat requests" is rendered only after a full refresh of the page.
If you need more information, please let me know
Try this :
#if(count($threads))
<div data-threads-count="{{ count($threads) }}">Chat requests</div>
#else
<div data-threads-count="{{ count($threads) }}">No chat requests</div>
#endif
Now you can access threads count by using data function in jquery ex :
$(selector).data('threads-count');
or
$(selector).attr('data-threads-count');
Both will return threads count
i hope it was useful 😊
Related
I'm trying to build a cart page for an e-commerce website. I'm having trouble figuring out the JS for calculating.. below I'm getting a file through AJAX call called products.json which has products information like id, name, imp, prices etc and an array called productsArray which has product ids saved of products I've clicked on their respective cart icons. Now the logic is if the products.json file contains the id of products present in the array I want it to display on the cart page. So when I click the products add to cart button, for whichever product I click it gets added to local storage and from there I get it and compare it with each of the products present in the JSON file. Now this is printing my product with all furnished information. Now I want to change the price when the quantity of product is changed. I've also added a code fo that below and that too works. When I click on 2 then the price gets multiplied by 2 and showcases it in HTML. similarly for other values. The problem is this works only for the first product. I'm unable to get the functionality working for all products even though the IDs are all same.. How do I tackle this issue? Also I need to be able to access all the product prices as you can see in the second image below, sum them up then update the total on the top and the right containers under various descriptions.. How do I do these as well? Pls help! Have been trying to crack this for past 3-4 days..
let products = new Set();
let counter = 0;
// adding click events to cart icon
document.body.addEventListener('click', e => {
if (e.target.closest('.shopping')) {
products.add(e.target.closest('.prod-card').id);
// adding number of products in cart icon
counter = Number(document.querySelector('#cart-badge').innerHTML) + 1;
document.querySelector('#cart-badge').innerHTML = String(counter);
};
// storing product ids in local storage
localStorage.setItem('Products_IDs', JSON.stringify(Array.from(products)))
});
// parsing JSON List for cart page
let RetrievedData = localStorage.getItem("Products_IDs");
let productsArray = JSON.parse(RetrievedData);
// for (i = 0; i < productsArray.length; i++){
// console.log(productsArray);
// }
let xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
let myProducts = JSON.parse(this.responseText);
for (i = 0; i < productsArray.length; i++) {
for (j = 0; j < myProducts.products.length; j++) {
if (productsArray[i] == myProducts.products[j].id) {
let ReturnedHTML2 = " ";
ReturnedHTML2 = `<div class="cart-items-holder" id='pdt-box'>
<div class='pdt-container' id='pdt-single'>
<img class='img-sweater' src="Images/${myProducts.products[j].imageName}.png" alt="Sweater Image">
<div class="pdt-text w-100">
<div class="text1">
<h6>${myProducts.products[j].name}</h6>
<p class="mb-0 text-secondary">Color : Multicolor</p>
<p class="mb-0 text-secondary">Seller : Indus Valley & Co</p>
<div class="forms mt-xl-3 mt-lg-3 mt-md-2 mt-sm-2 d-flex justify-content-start align-items-start">
<div class="form-group">
<label class='mr-2' for="exampleFormControlSelectSize"></label>
<select class="form-control" id="exampleFormControlSelectSize">
<option>Size : Onesize</option>
<option>S</option>
<option>M</option>
<option>L</option>
<option>XL</option>
<option>XXL</option>
</select>
</div>
<div class="form-group2 ml-3">
<label class='mr-2' for="exampleFormControlSelectQuantity"></label>
<select class="form-control" id="exampleFormControlSelectQuantity">
<option>QTY : 1</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select>
</div>
</div>
</div>
<div class="text2">
<p class='pricing mb-0'>Rs.<strong id='final-price'>${myProducts.products[j].priceAfterDiscount}</strong> <del id='initial-price'>Rs.${myProducts.products[j].price}</del><span
class="offer font-weight-bold ml-1">(60%Off)</span></p>
<small class="text-secondary">Delivery in 4 - 6 days</small>
</div>
</div>
</div>
<div class="options">
<a class="ml-3 mr-3 text-dark font-weight-bold" id='remove-btn' href="">REMOVE</a> | <a class="ml-3 mr-3 text-dark font-weight-bold" id='wishlist-btn' href="">ADD TO WISHLIST</a>
</div>
</div>
<br>`
document.querySelector('#cart-items-area').innerHTML += ReturnedHTML2;
sessionStorage.setItem("discounted_price", Number(document.getElementById('final-price').innerHTML))
document.getElementById('exampleFormControlSelectQuantity').onchange = function() {
if (document.getElementById('exampleFormControlSelectQuantity').selectedIndex == 1) {
price_1 = sessionStorage.getItem("discounted_price");
document.getElementById('final-price').innerHTML = price_1 * 1;
} else if (document.getElementById('exampleFormControlSelectQuantity').selectedIndex == 2) {
price_2 = sessionStorage.getItem("discounted_price");
document.getElementById('final-price').innerHTML = price_2 * 2;
} else if (document.getElementById('exampleFormControlSelectQuantity').selectedIndex == 3) {
price_3 = sessionStorage.getItem("discounted_price");
document.getElementById('final-price').innerHTML = price_3 * 3;
} else if (document.getElementById('exampleFormControlSelectQuantity').selectedIndex == 4) {
price_4 = sessionStorage.getItem("discounted_price");
document.getElementById('final-price').innerHTML = price_4 * 4;
} else {
price_default = sessionStorage.getItem("discounted_price");
document.getElementById('final-price').innerHTML = price_default;
}
}
}
}
}
}
};
xmlhttp.open("GET", "products.json", true);
xmlhttp.send();
[
Seeing that you've spent a few days on this already. I would consider it worth spending some time to refactor the existing code to be a bit more organized! :)
I see a lot of nested ifs and fors => extract them to separate functions
I see a big template containing an HTML document string => separate function taking 2 arguments & returns the fully rendered html document.
If you end up looking at this code for yet another day, at least it would help if you extracted every part into its own simpler function. you can also then run each function individually to test that it does what you expect this way! :) It helps a tonne to split things up!
Right now it's all one "big monster function" in the XMLHTTPRequest handler.
Also, there is a fair bit of repeated code in the bottom, Whenever you see this it should help guide you to where to reduce and simplify your code a bit!:
if (document.getElementById('exampleFormControlSelectQuantity').selectedIndex == 1) {
price_1 = sessionStorage.getItem("discounted_price");
document.getElementById('final-price').innerHTML = price_1 * 1;
} else if (/*repeated code*/) {
/* repeated code, with a single number changing 2, 3, 4... */
}
the conditional code is (almost) exactly the same, so you don't have to make the same document query for the same element in every case.
const selected_number = document.getElementById('exampleFormControlSelectQuantity').selectedIndex;
and you can re-use this like this:
if (selected_number == 1) {
price_1 = sessionStorage.getItem("discounted_price");
document.getElementById('final-price').innerHTML = price_1 * 1;
} else if (selected_number == 2) {
/* repeated code, with a single number changing 2, 3, 4... */
}
but now you can also just assume the number is... the number you need inside the conditional... so you can shorten the individual number checks to a single snippet of code like this:
price = sessionStorage.getItem("discounted_price");
document.getElementById('final-price').innerHTML = price * selected_number;
I have created a product card view in Laravel. the card has a simple "accordion" ('Show Details') - closed by default - that is managed by Vue.js as well as a Vue.js quantity counter that changes the weight value in grams if you add products. It all functions very well on the card's view and it looks like this (closed):
I have another view in which I query my DB for product names with Vue.js to display all products of the same name as a result. The problem is when the cards are displayed on that "parent" view, they all appear with the accordion open and the counter is not responsive. It looks like so:
As you can see, the tailwindcss code is rendered without a problem but the Vue.js is being completely ignored (Although the parent view's Vue.js functions work perfectly) What am I doing wrong? What am I missing here? Why are the directives inside the included blade being ignored?
Here is the Vue.js method that manages the (product cards) views integration onto the parent (product name search) view:
setGearItem(gearItem) {
this.gearItem = gearItem;
this.modal = false;
console.log(gearItem);
document.getElementById("displaySearch").innerHTML = "";
axios.get('/send-name-get-ids/' + this.gearItem)
.then((response) => {
console.log(response.data);
if (response.data.length === 0) {
document.getElementById("displaySearch").innerHTML = `"<strong>${gearItem}</strong>" was not found in our database. You can add it manually:`;
this.generalForm = true;
return;
} else {
for (let i = 0; i < response.data.length; i++) {
axios.get('/gearitem/' + response.data[i])
.then((response) => {
console.log(response.data);
document.getElementById("displaySearch").innerHTML += response.data;
this.generalForm = false;
})
.catch((error) => {
document.getElementById("displaySearch").innerHTML =
"No items to display";
console.log(error);
});
}
}
});
},
The problem is in the .innerHTML method as Vue.js ignores anything added via this method even if it's an AJAX. The solution consists on changing the controller to return a JSON and not a blade view, then using the JSON to populate a Vue.js component to create the item's card. the setGearItem() method was changed like so:
setGearItem(gearItem) {
this.gearItem = gearItem;
this.modal = false;
console.log(gearItem);
document.getElementById("displaySearch").innerHTML = "";
this.displayItemCard = false;
axios.get('/send-name-get-ids/' + this.gearItem)
.then((response) => {
console.log(response.data);
this.gearItemId = response.data[0];
if (response.data.length === 0) {
document.getElementById("displaySearch").innerHTML =
`<p class="text-gray-700 ">
<strong class="capitalize">${gearItem}</strong>
was not found on our database. <br>You're free to add it manually! </p>`;
this.generalForm = true;
return;
} else {
this.displayItemCard = true;
}
});
},
the displayItemCard just activates the card component on the view and displays the correct card according to the id.
I just deployed a website to test in "production" but when i try to go to the website some of my computer won't see one the results of my ng-repeat and some will see. If I go to the website when there's nothing displayed I look at the source code and I see the ng-repeat with each object of my array, but no html output on the screen. Here some of my code when I load my controller:
/**
* Function that send a request to get a list of posts.
* #return {Function} A promise.
*/
function retrievePosts() {
var defered = $q.defer();
// If the user is logged in we do a search by country, otherwise we get all the posts.
if($rootScope.user !== null && $rootScope.user !== undefined) {
PostService.searchPost({ countries: [$rootScope.user.country] }, function(err, posts) {
if(err) {
defered.reject(err);
}
else if(posts && posts.length > 0) {
defered.resolve(posts);
}
// If the previous condition is not true, we try to get all the posts, since the search by country didn't work.
else {
PostService.getAllPosts(function(err, posts2) {
if(err) {
defered.reject(err);
} else {
defered.resolve(posts2);
}
});
}
});
} else {
PostService.getAllPosts(function(err, posts) {
if(err) {
defered.reject(err);
}
else {
defered.resolve(posts);
}
});
}
return defered.promise;
}
This function is used to get an array of JSON posts object. Then I do a q.all like this:
$q.all([retrieveManufacturer(), retrieveCategories(), retrievePosts(), getTotalPosts(), retrieveGalleryPosts()]).then(function(results) {
$scope.manufacturers = results[0];
$scope.categories = results[1];
// Here we must cache the result and slice it, so that angular doesn't render
// a tone of post but 10 at a time.
postCache = results[2];
$scope.numberOfPostsToShow = 10;
$scope.posts = postCache.slice(0, $scope.numberOfPostsToShow);
// Some code to display the proper amount of post for each category.
var i = -1;
var max = results[3].length;
var groupedPostsCount = { };
var group;
while(++i < max) {
group = results[3][i];
// "_id" contains the name of the category.
groupedPostsCount[group._id] = group.count;
}
if(Object.keys(groupedPostsCount).length > 0){
$scope.categoriesPostCount = groupedPostsCount;
}
$scope.galleryPosts = results[4];
// Prepare the $scope.galleryPosts to be bound with posts.
buildGallery($scope.galleryPosts);
}, function(err) {
console.log(err);
});
Every task in $q.all gets executed and they all get resolved. I see them in my HTML like the categories, manufacturers, etc... Results[2] which are the array of posts are not null they really do have 500 posts in them. I try to call $scope.$apply() after buildGallery() method call, but nothing work. If I print {{ posts }} anywhere in my html i see the array of posts. But when they are in that ng-repeat:
<div class="ad-container" ng-repeat="post in posts" ng-click="viewPostDetails(post)">
<div class="ad-picture">
<table class="wrapper">
<tr>
<td><img ng-src="img/175/{{ post.mainImageName || post.imgUrls[0] }}" alt="No image provided"/></td>
</tr>
</table>
</div>
<div class="ad-info">
<span class="ad-info-title">{{ post.title }}</span>
<span class="ad-info-price">{{ post.country == 'Canada' ? (post.price | currency : "CA$") : (post.price | currency : "US$") }}</span>
<br />
<span>{{ post.country }}, {{ post.province }}, {{ post.createdAt | date }}</span>
<p>{{ post.description }}</p>
</div>
</div>
Of course this code is inside a div that has a controller bound to it.Like I said, it's really weird. On my development computer everything works perfectly, but some of the computers of my friend did work and others didn't. Here's the link to the website www.firearmsbin.com maybe the problem will occur on your computer. I tried on firefox, firefox for dev, edge, chrome and IE11.
Thanks.
I found out that it was adblock who was not displaying my div which as the class "ad-container". So every class in css that contains "ad" word get block.
I am starting with a simple TODO app with Aurelia, RethinkDB & Socket.IO. I seem to have problem with re-rendering or re-evaluating an object that is changed through Socket.IO. So basically, everything works good on the first browser but doesn't get re-rendered in the second browser while displaying the object in the console does show differences in my object. The problem is only on updating an object, it works perfectly on creating/deleting object from the array of todo items.
HTML
<ul>
<li repeat.for="item of items">
<div show.bind="!item.isEditing">
<input type="checkbox" checked.two-way="item.completed" click.delegate="toggleComplete(item)" />
<label class="${item.completed ? 'done': ''} ${item.archived ? 'archived' : ''}" click.delegate="$parent.editBegin(item)">
${item.title}
</label>
<i class="glyphicon glyphicon-trash"></i>
</div>
<div show.bind="item.isEditing">
<form submit.delegate="$parent.editEnd(item)">
<input type="text" value.bind="item.title" blur.delegate="$parent.editEnd(item)" />
</form>
</div>
</li>
</ul>
NodeJS with RethinkDB changefeeds
// attach a RethinkDB changefeeds to watch any changes
r.table(config.table)
.changes()
.run()
.then(function(cursor) {
//cursor.each(console.log);
cursor.each(function(err, item) {
if (!!item && !!item.new_val && item.old_val == null) {
io.sockets.emit("todo_create", item.new_val);
}else if (!!item && !!item.new_val && !!item.old_val) {
io.sockets.emit("todo_update", item.new_val);
}else if(!!item && item.new_val == null && !!item.old_val) {
io.sockets.emit("todo_delete", item.old_val);
}
});
})
.error(function(err){
console.log("Changefeeds Failure: ", err);
});
Aurelia code watching Socket.on
// update item
socket.on("todo_update", data => {
let pos = arrayFindObjectIndex(this.items, 'id', data.id);
if(pos >= 0) {
console.log('before update');
console.log(this.items[pos]);
this.items[pos] = data;
this.items[pos].title = this.items[pos].title + ' [updated]';
console.log('after update');
console.log(this.items[pos]);
}
});
// create item, only add the item if we don't have it already in the items list to avoid dupes
socket.on("todo_create", data => {
if (!_.some(this.items, function (p) {
return p.id === data.id;
})) {
this.items.unshift(data);
}
});
// delete item, only delete item if found in items list
socket.on("todo_delete", data => {
let pos = arrayFindObjectIndex(this.items, 'id', data.id);
if(pos >= 0) {
this.items.splice(pos, 1);
}
});
The socket.on("todo_update", ...){} is not making the second browser re-render but showing the object in the console before/after update does show differences in the object itself. I even changed the todo title property and that too doesn't get re-rendered.
How can I get Aurelia to re-render in my second browser with the new object properties? Don't be too hard on me, I'm learning Aurelia/RethinkDB/NodeJS/Socket.IO all the same time...
Aurelia observes changes to the contents of an array by overriding the array's mutator methods (push, pop, splice, shift, etc). This works well for most use-cases and performs really well (no dirty-checking, extremely lightweight in terms of memory and cpu). Unfortunately this leaves one way of mutating an array that aurelia can't "see": indexed assignment... eg myArray[6] = 'foo'. Since no array methods were called, the binding system doesn't know the array changed.
In your case, try changing this:
// update item
socket.on("todo_update", data => {
let pos = arrayFindObjectIndex(this.items, 'id', data.id);
if(pos >= 0) {
console.log('before update');
console.log(this.items[pos]);
this.items[pos] = data; // <-- change this to: this.items.splice(pos, 1, data);
this.items[pos].title = this.items[pos].title + ' [updated]';
console.log('after update');
console.log(this.items[pos]);
}
});
How to Write Condition on data which is fetching from Json to Angularjs?
Example : if user FIRM NAME exists Show else if user FULL NAME exists Show else Show REALNAME
I have a working Example of fetching data
at line number 25 <h3 class="moduletitle">Name : {{ module.realname }}</h3>
Please See that in PLUNKER
I hope i will get the working code update along with PLUNKER
I can suggest you have a function that returns the entity in which you want to display. Then using ng-show / ng-hide to display/hide the things you want.
Example:
function pseudoDecide(){
var displaythis = "";
if(/*boolean exp*/){ displaythis = "firm" }
else if(/*boolean exp*/) { displaythis = "full" }
else(/*boolean exp*/) { displaythis = "real" }
return displaythis;
}
Then <div ng-show="{{psedoDecide() === 'firm'}}>" etc etc, something like that.
With AngularJS 1.1.5+, you can use the ternary operator inside an expression. In your case, I believe you want something like:
<h3 class="moduletitle">Name : {{ module.firmname ? module.firmname : (module.fullname ? module.fullname : module.realname)) }}</h3>
If you don't want a nested ternary in your template, you could also go this route:
Somewhere in your controller:
$scope.pickName = function (module) {
var val;
if (module.firm_name) {
val = module.firm_name;
} else if (module.full_name) {
val = module.full_name;
} else {
val = module.realname;
}
return val;
};
And in your template:
<h3 class="moduletitle">Name : <span ng-bind="pickName(module)"></span></h3>