I’m starting with vue js and I’m listing some data from database. More specifically posts with title, description and images.
I have Edit and Delete buttons. All posts are loaded using v-for. So when I click to edit one post, all the posts are “openning” to be edited.
I need to open the editing only in one post at a time. I mean, the specific post I really want to edit.
I made some progress with title input and with image delete badge but still need to work on Save and Cancel buttons (they open in all posts) and input files (when I choose files in second post for example, they load into first post).
<div id="app" class="row mb-50">
<div v-for="(item, index) in tours" v-bind:key="item.id" id="tours" class="col-md-12 mb-30">
<div class="tour-list">
<div class="tour-list-title">
<p>
<!-- here I can block input title to be disabled on other posts not than the specific one and I intend to do the same with textarea -->
<input class="inputEdit" type="text" ref="item.id" v-model="item.title"
:disabled="editingTour !== item.id" :class="{inputEditOpen: !editingTour}" />
</p>
</div>
<div class="tour-list-description">
<p>
<textarea class="inputEdit" :disabled="!editingTour" v-model="item.description"
:class="{inputEditOpen: !editingTour}">
{{ item.description }}
</textarea>
</p>
</div>
<div class="tour-list-pics">
<div class="row mb-20">
<div class="col-md-12">
<ul class="pics-list">
<li v-for="(image, index) in item.images">
<!-- here I could hide badge -->
<span :hidden="editingTour !== item.id" class="badge"
#click="$delete(item.images, index), deleteImage(image.imageID)">
<i class="fa fa-fw fa-times-circle"></i>
</span>
<div class="pics-list-image-container img-fluid cursor-pointer"
v-bind:style="{'background-image': 'url(http://localhost/tours/'+image.image + ')' }"
#click="openModal = true, showModal(image.image)">
</div>
</li>
<li v-if="urls" v-for="(url, key) in urls" :key="key">
<div id="preview" :ref="'url'" class="pics-list-image-container img-fluid"></div>
</li>
<li v-if="editingTour" class="add-pics-item">
<div :hidden="editingTour !== item.id" class="mt-10">
<label for="file-upload" class="custom-file-upload">
<img class="img-fluid" src="./img/plus-icon.png">
</label>
<input id="file-upload" type="file" #change="onFileChange"
name="files[]" multiple />
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="tour-list-options">
<div class="row">
<div class="col-md-6">
<span>
<button #click="editingTour = item.id" v-if="!editingTour"
class="btn border btn-circle tour-list-edit-btn">Edit</button>
</span>
<span>
<button #click="editTour(item)" v-if="editingTour"
class="btn border btn-circle tour-list-edit-btn">Save</button>
</span>
<span>
<button #click="clearInput" v-if="editingTour"
class="btn border btn-circle tour-list-delete-btn">Cancel</button>
</span>
<span>
<button #click="deleteTour(item.id, index)" v-if="!editingTour"
class="btn border btn-circle tour-list-delete-btn">Delete</buton>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
Update
If I use
<button #click="editTour(item)" v-if="editingTour == item.id" class="btn border btn-circle tour-list-edit-btn">Save</button>
all others Save buttons get hidden.
I think you can use add to each object of list new property isEditing and look for it in each item of the loop to check Save/Edit show.
Now your one prop editingTour can't be used for multiple edit, it can't store array of edited items id.
Template of buttons would look like:
<span>
<button #click="item.isEditing = item.id" v-if="!item.isEditing"
class="btn border btn-circle tour-list-edit-btn">Edit</button>
</span>
<span>
<button #click="editTour(item)" v-if="item.isEditing"
class="btn border btn-circle tour-list-edit-btn">Save</button>
</span>
<span>
<button #click="clearInput(item)" v-if="item.isEditing"
class="btn border btn-circle tour-list-delete-btn">Cancel</button>
</span>
<span>
<button #click="deleteTour(item.id, index)" v-if="!item.isEditing"
class="btn border btn-circle tour-list-delete-btn">Delete</button>
</span>
Related
when clicked on a button there should be a div to be shown that "Are u sure, u want to delete"
else other div should be shown.
i am trying either ways using ng-show or show()
<button
class="button-default button-m panel-heading-margin"
type="button"
ng-if="!$last"
ng-click="deleteButton();"
>
<i class="icon16 icon-delete v-sub di-block mr-0"></i>
</button>
<div class="modal-footer mt-10 p-0">
<div
id="deleteview"
class="bg-gray-light row"
ng-show="$scope.displayModal"
>
<div class="col-md-9">
<h4 class="p-15 text-left">
You are going to <b>Delete</b> the <b>Mapping</b> you have
selected. Are you sure you want to continue?
</h4>
</div>
<div class="col-md-3">
<div class="pt-25 text-right pr-5">
<button class="button-cancel button-m">Cancel</button>
<button id="deletesinglemap" class="button-m button-primary">
Delete
</button>
</div>
</div>
</div>
<div id="addview" class="pull-right p-20" ng-hide="$scope.displayModal">
<span class="button-cancel" data-dismiss="modal">Cancel</span>
<button id="addmapping" class="button-m button-primary" type="button">
Add
</button>
</div>
</div>
Controller:
$scope.slideUpModal = function () {
$scope.displayModal = true;
$("#deleteview").show();
$("#addview").hide();
};
when clicked on a button there should be a div to be shown that "Are u sure, u want to delete"
else other div should be shown.
i am trying either ways using ng-show or show()
I have downloaded a bootstrap template for e-commerce that I want to integrate in odoo Qweb templating. In products grid view there is non functional pagination and products filtering parameters, that I want to make functional using isotope grid.
In image I have marked the filters to apply.
Code for products grid on which I want to apply pagination and products filtration.
<div t-attf-class="isotope-grid filter-grid cols-3 rows-1 mb-2" itemsPerPageDefault="6">
<div class="gutter-sizer"></div>
<div class="grid-sizer"></div>
<!-- Product-->
<t t-foreach="Products" t-as="prods">
<div t-attf-class="grid-item scid{{prods.product_sub_cat_id.id}} cid{{prods.product_type_id.id}} brid{{prods.product_brand_id.id}}">
<div class="product-card">
<div class="product-badge text-danger">
<t t-esc="prods.discount" />
% Off
</div>
<a class="product-thumb" t-attf-href="/template/shop-single/{{slug(prods)}}">
<img t-att-src="image_data_uri(prods.first_image)" style="height: 200px;" alt="Product" />
</a>
<h3 class="product-title">
<a t-attf-href="/template/shop-single/{{slug(prods)}}">
<t t-esc="prods.name" />
</a>
</h3>
<h4 class="product-price">
<del>
pkr
<t t-esc="prods.price" />
</del>
pkr
<t t-esc="prods.price - ((prods.discount*prods.price)/100)" />
</h4>
<div class="product-buttons">
<button class="btn btn-outline-secondary btn-sm btn-wishlist" data-toggle="tooltip" title="Whishlist">
<i class="icon-heart"></i>
</button>
<form t-attf-id="fa{{prods.id}}" t-attf-action="/template/update-mycart" class="d-inline-block" method="GET">
<input type="hidden" t-attf-id="ia{{prods.id}}" t-att-name="product_id" t-attf-value="{{prods.id}}" title="" />
</form>
<a t-attf-id="{{prods.id}}" onclick="addCart(this)" class="btn btn-outline-primary btn-sm" data-toast="" data-toast-type="success" data-toast-position="topRight" data-toast-icon="icon-circle-check" data-toast-title="Product" data-toast-message="successfuly added to cart!">
Add to Cart
</a>
</div>
</div>
</div>
</t>
</div>
filters want to apply
I am working on a post system with likes where the user can toggle the post`s like I have done everything correctly except the last step, the problem inside my v-for loop I fetch likes table from post-like relation(many to many since likes table has user_id and post_id) but it is iterating my button even when I add a condition look here-> duplicated like button, I have tried many things v-if, v-show I think the problem is with my algorithm I hope someone can fix that for me thanks.
<div class="panel panel-white post panel-shadow" v-for="post in posts" >
<div class="post-heading">
<div class="pull-left image">
<img v-bind:src="'img/profile/' + post.user.photo" class="img-circle avatar" alt="user profile image">
</div>
<div class="pull-left meta">
<div class="title h5">
<b>{{post.user.name}} </b>
made a post.
</div>
<h6 class="text-muted time">{{post.created_at | hour}}</h6>
</div>
</div>
<div class="post-description">
<p>{{post.content}}</p>
<div class="stats">
<button class="btn btn-default stat-item" #click.prevent="addLike(post.id)">
<i class="fa fa-thumbs-o-up" aria-hidden="false" style="color: blue" v-for="(like) in post.likes" v-bind:style="like.user_id===id && like.post_id===post.id?'color: blue;':'color: gray;'" > Like {{post.likes.length}}
</i> <!-- here is the duplicate problem-->
</button>
<a class="btn btn-default stat-item" #click.prevent>
<i class="fa fa-reply-all"> {{post.comments.length}}</i> Comments
</a>
</div>
</div>
<comment-input :post="post" :userId="id" :userPhoto="userPhoto"></comment-input>
<ul class="comments-list" v-for="comment in post.comments?post.comments:''">
<comments :comment="comment" :userId="id" :userPhoto="userPhoto"></comments>
</ul>
</div>
<hr>
</div>
</div>
Don't loop through the button element, try to use a method likedBythisUser to check if the current user liked the post in order to bind it to the button style :
methods:{
likedBythisUser(post,id){
return post.likes.find(like=>{
return like.user_id===id && like.post_id===post.id;
}) // return a boolean value
}
}
template :
<button class="btn btn-default stat-item" #click.prevent="addLike(post.id)">
<i class="fa fa-thumbs-o-up" aria-hidden="false" style="color: blue" bind:style="likedBythisUser(post,id)?'color: blue;':'color: gray;'" > Like {{post.likes.length}}
</i> <!-- here is the duplicate problem-->
</button>
Is there any way to access *ngFor variable item outside the current div. in my case the booking(item) method not able to access item variable. any possible way?
<div class="cart-item" *ngFor="let item of items">
<small>
<img [src]="item.imagePath" alt="{{item.name}}"
class="img-responsive" style="max-height: 100px" width="120px">
<p>Name: {{item.name}}</p>
<p>Price: {{item.price}}</p>
<button class="btn btn-danger" (click)="deleteItem(item)">X</button>
<hr/>
</small>
</div>
<button class="btn btn-primary btn-lg" (click)="booking(item)"
style="margin-right: 30px;">Book Now</button>
No, you need to put it inside the div. If you want to preserve your structure, then you should wrap your code in another div and have that use the ngFor directive instead.
The way ngFor works, is it will create an element (in your case, the <div class="cart-item"> multiple times, once for each item in the loop. The button will be placed after all the cart item elements, so how could it know which item it should refer to?
I think what you're trying to do is to put one button for each of your cart items. in this case, you would modify your code as following:
<div class="cart-item" *ngFor="let item of items">
<small>
<img [src]="item.imagePath" alt="{{item.name}}" class="img-responsive" style="max-height: 100px" width="120px"/>
<p>Name: {{item.name}}</p>
<p>Price: {{item.price}}</p>
<button class="btn btn-danger" (click)="deleteItem(item)">X</button>
<hr/>
</small>
<button class="btn btn-primary btn-lg" (click)="booking(item)" style="margin-right: 30px;">Book Now</button>
</div>
or, if you'd like to preserve your structure:
<div *ngFor="let item of items">
<div class="cart-item">
<small>
<img [src]="item.imagePath" alt="{{item.name}}" class="img-responsive" style="max-height: 100px" width="120px"/>
<p>Name: {{item.name}}</p>
<p>Price: {{item.price}}</p>
<button class="btn btn-danger" (click)="deleteItem(item)">X</button>
<hr/>
</small>
</div>
<button class="btn btn-primary btn-lg" (click)="booking(item)" style="margin-right: 30px;">Book Now</button>
</div>
I am using http://fineuploader.com/ and Twitter bootstrap
The html code for the uploading files looks like this
<ul class="qq-upload-list-selector">
<li class="col-lg-3 col-md-4 col-xs-6 thumb">
<div class="qq-progress-bar-container-selector">
<div class="qq-progress-bar-selector qq-progress-bar"></div>
</div>
<span class="qq-upload-spinner-selector qq-upload-spinner"></span>
<img class="qq-thumbnail-selector" qq-max-size="100" qq-server-scale>
<span class="qq-edit-filename-icon-selector qq-edit-filename-icon"></span>
<span class="qq-upload-file-selector qq-upload-file"></span>
<input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
<span class="qq-upload-size-selector qq-upload-size"></span>
<a class="qq-upload-cancel-selector btn-small btn-warning" href="#">Cancel</a>
<a class="qq-upload-retry-selector btn-small btn-info" href="#">Retry</a>
<a class="qq-upload-delete-selector btn-small btn-warning" href="#">Delete</a>
<a class="qq-upload-pause-selector btn-small btn-info" href="#">Pause</a>
<a class="qq-upload-continue-selector btn-small btn-info" href="#">Continue</a>
<span class="qq-upload-status-text-selector qq-upload-status-text"></span>
<a class="view-btn btn-small btn-info hide" target="_blank">View</a>
</li>
</ul>
I want to change the <ul></ul><li></li> tags to <div> because I want the result to appear in a bootstrap grid. When I change the code can't I get any upload result for my uploaded files. Looks like new li-tags generates by fineuploader javascript.
How do I use div instead and so that I can display the result in a bootstrap grid?
Tested this
<div class="qq-upload-list-selector col-lg-3 col-md-4 col-xs-6">
<div class="qq-progress-bar-container-selector">
<div class="qq-progress-bar-selector qq-progress-bar"></div>
</div>
Rest of the code ....
</div>
Fine Uploader is expecting a container inside of the qq-upload-list-selector to to hold the file item. Consider adding another <div> as the only child of the qq-upload-list-selector.
So...
<div class="qq-upload-list-selector col-lg-3 col-md-4 col-xs-6">
<div>
<div class="qq-progress-bar-container-selector">
<div class="qq-progress-bar-selector qq-progress-bar"></div>
</div>
Rest of the code ....
</div>
</div>
Why do you need a <div> for this? There's nothing special about a <div>. Just modify the style of the list item/list appropriately. Fine Uploader doesn't insert <li> tags if they aren't in your template.