Why Can't I Add The Same Image To Shopping Cart More Than Once - html

What I'm trying do is when the user adds item to cart more than once I would like it to be a separate image instead of just adding to the quantity. I have it now where if product exist in the cart it just adds to the quantity. The reason I need this change is because now there are product sizes associate with the product using radio buttons and this won't work the way it currently is. I tried manipulating the code but I still get same result or get cart is empty. Can someone point me in the right direction. I have included code snippet.
cart.service.ts
getCartItems(): Observable<CartItem[]> {
return this.http.get<CartItem[]>(cartUrl).pipe(
map((result: any[]) => {
let cartItems: CartItem[] =[];
for(let item of result) {
let productExists = false
for(let i in cartItems){
if(cartItems[i].productId === item.product.id){
cartItems[i].qty++
productExists = true
break;
}
}
if (!productExists){
cartItems.push( new CartItem(item.id,item.product,item.imageUrl));
}
}
return cartItems;
})
);
}
Thanking You In Advance

Are you sure you tried to modify the code?
In this chunk you are doing the quantity of the product and setting the flag for pushing or not the item with the image
for(let i in cartItems){
if(cartItems[i].productId === item.product.id){
cartItems[i].qty++
productExists = true
break;
}
In this other chunk you literally are reading the flag from the last "for" and pushing if the flag is false
if (!productExists){
cartItems.push( new CartItem(item.id,item.product,item.imageUrl));
}
You can do a for to push all the items without any validations or adding to the "qry"

I took out all the validation like Cayman suggested and now it works the way I need it to for the application. The previous code was checking if exist which I don't need because I want to load another product even if it does exist. Part of previous code is still good for situations when you don't want to add a product that already exist for example a wish list or favorites. Correct code snippet without validation below:
getCartItems(): Observable<CartItem[]> {
return this.http.get<CartItem[]>(cartUrl).pipe(
map((result: any[]) => {
let cartItems: CartItem[] =[];
for(let item of result) {
cartItems.push( new CartItem(item.id,item.product,item.imageUrl));
}
return cartItems;
})
);
}
PDH

Related

How to get multiple selected checkbox item from multiple checkbox list in angular

i have minimal reproduce here https://stackblitz.com/edit/angular-uwfsyv?file=app%2Fapp.component.html, there i have 2 array,checkboxesDataList and checkboxesDataList2 i successfully get the checked label from checkboxesDataList but that's just for an example.
but what i wanted to get in my project is similar to checkboxesDataList2 inside here i have object question and checkboxesDataList don't have that so this function
fetchSelectedItems() {
this.selectedItemsList = this.checkboxesDataList.filter((value, index) => {
return value.checked;
});
}
won't work immediately if i change this.checkboxesDataList to this.checkboxesDataList2 how can i make it work?
do you want to has a function like?
getDataChecked()
{
return this.checkboxesDataList2.question
.map(x=>x.options.filter(o=>o.checked))
.reduce((acc, value)=>[...acc,...value])
}

Angular 6 - How to stop infinite polling in subscribe()

So I want to show an icon based on whether or not the number of projects in my list is > 3. I am using this getProjects() function that I need to subscribe to in order to get the data. I am setting a boolean when I subscribe that checks the number of projects in the list, then in my HTML, I use a ngIf to show the icon based on the boolean. I am able to get it to show correctly, however, I think I am constantly polling in my subscribe, and setting this boolean over and over again because it is making my webpage run really slow.
I have already tried the take(1) method which doesnt seem to stop the subscription, as well as set it to a "this.variable" scope inside my component. I am currently using event emitters however that is not working either.
This is my code so far,
Function that I subscribe to (in a different component):
getProjects(): Observable<ProjectInterfaceWithId[]> {
const organizationId = localStorage.getItem('organizationId');
return this.firestoreService.collection('organizations').doc(organizationId)
.collection('projects').snapshotChanges()
.pipe(
map(actions => actions.map(a => {
const data = a.payload.doc.data() as ProjectInterface;
const id = a.payload.doc.id;
return {id, ...data} as ProjectInterfaceWithId;
})),
map(list => {
if (list.length !== 0) {
this.buildProjectLookup(list);
this.projects = list;
return list;
}
})
);
}
Function that i use to get the data and set the boolean:
#Input() toggle: boolean;
#Output() iconStatus = new EventEmitter();
displayIcon() {
this.projectService.getProjects()
.pipe(take(1))
.subscribe(
list => {
if(list.length >= 3){
this.toggle = true;
this.iconStatus.emit(this.toggle);
}
});
}
HTML:
<i *ngIf="displayIcon()" class="material-icons">list</i>
Is there any way for me to literally just check the list length once so I don't get caught in this subscription loop? Thank you in advance!
It looks like it could be happening due to the ngIf referring to the displayIcon() method.
Every time change detection runs within your component, this method will be called. If your component is using default change detection, this will be very often.
see https://blog.angular-university.io/how-does-angular-2-change-detection-really-work/ for more
One way this could be fixed is by making the ngIf refer to a variable instead.
For example, you could set a projects$ observable using
this.projects$ = this.projectService.getProjects()
.pipe(
take(1),
tap(projects => this.iconStatus.emit(projects.length >= 3))
);
This observable should likely be instantiated in your ngOnInit() method.
Then in your template you can use
<i *ngIf="(projects$ | async)?.length >= 3" class="material-icons">list</i>

Problems trying to display JSON data in a django-tables2 table

I have django-tables2 set up and working well. I have set my table to be able to update checkbox columns directly from the displayed list. However when my displayed table paginates and I update a value it refreshes the entire page thus sending me back to the first page and I then have to click 'next' to get back to where I was. So I thought it might be a good idea to throw knockout.js into the mix to bind my individual columns to the corresponding data in my postgres database. According to the blurb this would allow me to simply refresh the item clicked on without having to refresh the entire page. I read the tutorial for knockout.js and all seems great and exactly what I am looking for. I've modified my views and written my js file etc and I am almost there. I have the JSONResponse from my views.py returning the correct number of rows, however, my django-tables2 tables are rendering each record as a header (ie th) in my table instead of the data as a row (ie td). Feeling like I've fallen at the last hurdle, I was wondering if anyone can shed any light on how I can fix this last bit of the puzzle please.
view.py
def mydatalist(request):
data = []
user = get_current_user()
query = Q(user_fkey=user.id)
query.add(Q(deleted__isnull=True), Q.AND)
query.add(Q(master=True), Q.AND)
tasks = Task.objects.filter(query)
for task in tasks:
data.append({"code":task.code, "name":task.name, etc})
return JsonResponse(data, safe=False)
my .js file
function Task(data) {
this.code = ko.observable(data.code);
this.name = ko.observable(data.name);
etc
}
function TaskListViewModel() {
// Data
var self = this;
self.tasks = ko.observableArray([]);
$.getJSON('http://myweb.org/tasks/mydatalist/', function (data) {
if(data){
var mappedTasks = $.map(data, function (item) {
return new Task(item);
});
} else {
alert('data empty!');
}
self.tasks(mappedTasks);
});
}
ko.applyBindings(new TaskListViewModel());
my django-tables2 tables.py file
class MasterTable(ColumnShiftTable):
code = tables.Column(attrs={'th':{'class':'centered nodec'}})
name = tables.LinkColumn(attrs={'th':{'class':'centered nodec'}})
etc
class Meta:
model = Task
fields = ('code','name', etc)
template_name = 'django_tables2_column_shifter/bootstrap3.html'
attrs={'id':'masterlist', 'class': 'table table-noborder', 'data-bind': 'foreach: tasks, visible: task().length > 0'}
row_attrs={'id': lambda record: record.pk}
So basically everything is kind of working except that when rendered, my django-tables2 table is rendering 11 headers and no data rows instead of 1 header and 10 data rows.
If anyone can shed any light I really would appreciate it or alternatively if someone can suggest another way to achieve not having to refresh the entire page each time, that would be great also.

Need to filter content on page by single array property on user corresponding button click in Angular 2

So, I am very confused here. I want to filter books that are already presented on the page by a value of a property from its array and that property is its specific Category(Philosophy, Classic, Poetry, etc...) when user click on the specific corresponding button on the panel.
Here is source-code: https://github.com/EgomortIncognitus/bookstore
This is my first Angular project, and I am quite a beginner in all of this, so I know that StackOverflow is not a "write code for me" service, but I genuinely want to understand this in depth as I do not have a single idea how to do this. Please, if you can provide me step-by-step examples I would be truly grateful to learn from you. Thank you in advance, big time.
You will do the filtering on your book-listing.component.ts:
You declare an array of categories which we instantiate with a first value 'All' so later we'll be able to reset the filter and to show all books:
categoryArray = ['All'];
Then, to be able to go back and forth with filtering we keep the books array only for display filtered books and we declare another booksDatasource array where we are going to keep the books list unmodified, as received from the service. This way, each time we filter on booksDatasource and add the filtered result to books for display.
booksDatasource: Array<any> = [];
After this, we modify the ngOnInit like this:
ngOnInit() {
this.booksService.getAllBooks()
.subscribe(
data => {
this.booksDatasource = data;
this.books = this.booksDatasource;
this.fillCategory(this.booksDatasource, this.categoryArray);
},
error => this.error = error.statusText
);
}
First, we fill the booksDatasource with all data, then we bind booksDatasource to books for the first time to show all books and we call the new added method fillCategory in which we iterate the datasource and extract all categories we have and add then to categoryArray:
fillCategory(data, categoryArray) {
for (const book of data) {
if (categoryArray.indexOf(book.category) === -1) {
categoryArray.push(book.category);
}
}
}
On book-listing.component.html, we add a new select that will display all the categories we have on categoryArray and we bind onChange event to trigger the categoryChanged() on component:
<div class="col-sm-4">
<label for="sort-field">Category</label>
<select (change)="categoryChanged($event.target.value)" name="cat-field" id="cat-field" class="form-control">
<option
*ngFor="let cat of categoryArray"
[value]="cat">
{{ cat }}
</option>
</select>
</div>
On the categoryChanged(cat) we pass the selected category from the select and we filter the booksDatasource for books having the passed category and we add them to books array for display:
categoryChanged(cat) {
if (cat === 'All') {
this.books = this.booksDatasource;
} else {
this.books = this.booksDatasource.filter(item => {
if (item.category === cat) {
return true;
}
return false;
}
);
}
}
I forked your repository, added the working code and made a pull request with the changes so you'll have all this working on your repo.

taking values separately using local storage in html5

I am making an app in html5.It is like a quiz based app. I am randomly fetching questions from the XML and displaying it one by one.I am using page navigation for that. After completing and submitting your answer u will switch to other page.if once i submit my answer i cannot attempt it back. but i can see the feedback and score on switching to that page that is my problem. I have display that feedback and score and to store it in local storage. i am able to do local storage but values that i am getting is overriding. so i am getting last submitted value.Now my concern is to divide that values navigation number wise.right now what is happening if i submit my answer and suppose i am at navigation number 3 n i am looking at navigation part 1 then there also i am getting last submitted value not the part 1 value.Please give ur suggestion and help me out for that.
Here is the code snippet:
//for navigation of pages
$(document).ready(function (){
/*$(document).bind("contextmenu",function(e){
return false;
});*/
var obj;
total=x.length;
for(var j=0;j<x.length;j++)
{
if(j==0)
{
$("#navigationlist").append('<li>'+(j+1)+'</li>');
display_nav(j,$("#selected_link"))
}
else
$("#navigationlist").append('<li>'+(j+1)+'</li>');
}
$("#next").bind("click",function (){
$(".navg").each(function(index){
if($(".navg").length==(i+1))
{
if(index==0)
obj=$(this);
}
else
{
if(index==(i+1))
obj=$(this);
}
});
for(var j=0;j<xmlDoc.getElementsByTagName("question").length;j++)
{
xmlDoc.getElementsByTagName("question")[j].removeAttribute("status");
}
$("#btnSubmit").attr("disabled","false");
$("#btnSubmit").attr("onclick","checekAnswer()");
display_nav(0,obj)
}
else
display_nav((i+1),obj)
});
});
and
correctAnswers++;
localStorage.setItem('feedback',JSON.stringify(feedback[0].childNodes[0].nodeValue));
$("#feedback").append(score[0].childNodes[0].nodeValue);
$("#feedback").append("<br/>");
$("#feedback").append(feedback[0].childNodes[0].nodeValue);
}
else
{
//var val = [];
//val.push(feedback[0].childNodes[0].nodeValue);
//localstorage.setItem('feedback', JSON.stringify(val));
//localStorage.setItem('feedback',JSON.stringify(feedback[0].childNodes[0].nodeValue));
//alert(localStorage.getItem("feedback"));
/*var v={"test":feedback[0].childNodes[0].nodeValue};
localStorage.setItem('feedback',v);
alert(localStorage.getItem('feedback'));*/
scores1.push(feedback[0].childNodes[0].nodeValue);
localStorage.setItem("highscores",JSON.stringify(scores1));
var scores = localStorage.getItem("highscores");
alert(scores);
scores = JSON.parse(scores);
alert(scores[0]);
$("#feedback").html(score[1].childNodes[0].nodeValue);
$("#feedback").append("<br/>");
$("#feedback").append(feedback[0].childNodes[0].nodeValue);
$("#feedback").append("hello");
}
//$("#counter").html("left="+xPos+",top="+yPos);
$("#trFeedBack").show("slow");
display_nav(j,obj)
}
} // end function
If I understand your question, your problem is to store items with same name but related to different pages.
LocalStorage being defined by domain, and not by page, you must change the keys you use. The usual solution is to prefix the names you want.
For example :
localStorage['pages.12.feedback'] = "the feedback I'm giving related to page 12";
localStorage['global.feedback'] = "the feedback I'm giving related to the global site";
(you'll notice I use the short notation, that I find more readable that using setItem)