I am using MeteorJS (So great :) ), to develop simple app. I want to use masonry, so I am using sjors:meteor-masonry package.
When I use this code everything works fine:
var itemsData = [
{
title: 'First item',
description: 'Lorem 1',
price: 20
},
{
title: 'Secounde item',
description: 'Lorem 2',
price: 40
},
{
title: 'Third item',
description: 'Lorem 3',
price: 10
},
{
title: 'Fourth item',
description: 'Lorem 4',
price: 10
},
{
title: 'Five item',
description: 'sit 4',
price: 10
}
];
Template.itemsList.helpers({
items: itemsData
});
Template.itemsList.rendered = function() {
var container = document.querySelector('#main');
var msnry = new Masonry( container, {
// options
columnWidth: 200,
itemSelector: '.item'
});
};
But when I change part (code) for Template.itemsList.rendered to masonry don't work:
Template.itemsList.helpers({
items: function() {
return Items.find();
}
});
Any ideas ?
EDIT
myapp/lib/collections/items.js
Items = new Mongo.Collection('items');
And it is populated whit data from mongoshell. Data is ok, but masonry dont work.
EDIT 2
Masonry stops animating on screen resize and grid is not working as it should. No errors.
myapp/client/templates
<template name="itemSingle">
<div id="profile-widget" class="panel item">
<div class="panel-heading">
</div>
<div class="panel-body">
<div class="media">
<div class="media-body">
<h2 class="media-heading">{{title}}</h2>
{{description}}
</div>
</div>
</div>
<div class="panel-footer">
<div class="btn-group btn-group-justified">
<a class="btn btn-default" role="button"><i class="fa fa-eye"></i> 172</a>
<a class="btn btn-default" role="button"><i class="fa fa-comment"></i> 34</a>
<a class="btn btn-default highlight" role="button"><i class="fa fa-heart"></i> 210</a>
</div>
</div>
</div>
</template>
<template name="itemsList">
<div id="main">
{{#each items}}
{{> itemSingle}}
{{/each}}
</div>
</template>
I encountered the same problem, without never finding the perfect solution.
I tried to resolve with the setTimout() workaround :
Template.main.rendered = function() {
setTimeout(function() {
$('#container').masonry({
columnWidth: 35,
itemSelector: '.thumb',
gutter: 10,
isFitWidth: false
});
}, 1);
}
Related
HTML and simple JS (no react / vue).
I need to do a list of cards and would like to do a loop to avoid repeating the html.
My current code :
<div id="products-cards-container">
<div class="products-cards">
<div class="product-header">
<img src="../assets/img/image1.png"/>
</div>
<div class="product-content">
<h4>title 1</h4>
<p>super content 1</p>
</div>
<button class="info-button">+ info</button>
</div>
<div>
<div class="product-header">
<img src="../assets/img/cards/products/image2.png"/>
</div>
<div class="product-content">
<h4>title 2</h4>
<p>super content 2</p>
</div>
<button class="info-button">+ info</button>
</div>
<div>
<div class="product-header">
<img src="../assets/img/cards/products/image-3.png"/>
</div>
<div class="product-content">
<h4>title 3</h4>
<p>blablablablbalbalbabla blablaba</p>
</div>
<button class="info-button">+ info</button>
</div>\
</div>
I am trying to return html
script.js
const valuesCards = [
{
image: '../img/image1.png',
title: 'title 1',
content: 'super content 1',
},
{
image: '../img/image2.png',
title: 'title 2',
content: 'super content 2'
},
{
image: '../img/image-3.png',
title: 'title3',
content: 'blablablablbalbalbabla blablaba'
},
]
creating a function that inserts the list of cards in the .products-cards div :
function returnCards() => {
----- AND HERE I AM STUCK
(as well, all tries I did with a simple array / object returned only the last info) ----
}
Use Array.prototype.map function and a template literal.
const container = document.getElementById('products-cards-container');
const valuesCards = [{
image: '../img/image1.png',
title: 'title 1',
content: 'super content 1',
},
{
image: '../img/image2.png',
title: 'title 2',
content: 'super content 2'
},
{
image: '../img/image-3.png',
title: 'title3',
content: 'blablablablbalbalbabla blablaba'
},
]
function returnCards(valuesCards) {
return "<div class=\"products-cards\">" + valuesCards.map(valuesCard => `
<div>
<div class="product-header">
<img src="${valuesCard.image}"/>
</div>
<div class="product-content">
<h4>${valuesCard.title}</h4>
<p>${valuesCard.content}</p>
</div>
<button class="info-button">+ info</button>
</div>`).join('') + "</div>";
}
container.innerHTML = returnCards(valuesCards);
<div id="products-cards-container"></div>
You can do it this way
const valuesCards = [
{
image: '../img/image1.png',
title: 'title 1',
content: 'super content 1',
},
{
image: '../img/image2.png',
title: 'title 2',
content: 'super content 2'
},
{
image: '../img/image-3.png',
title: 'title3',
content: 'blablablablbalbalbabla blablaba'
},
];
let cardHTML = '';
valuesCards.map(element => {
cardHTML += '<div> \
<div class="product-header"> \
<img src="'+element.image+'"/> \
</div> \
<div class="product-content"> \
<h4>'+element.title+'</h4> \
<p>'+element.content+'</p> \
</div> \
<button class="info-button">+ info</button> \
</div> \
';
});
document.getElementsByClassName('products-cards')[0].innerHTML = cardHTML;
<div id="products-cards-container">
<div class="products-cards">
</div>
</div>
const valuesCards = [
{
image: '../img/image1.png',
title: 'title 1',
content: 'super content 1',
},
{
image: '../img/image2.png',
title: 'title 2',
content: 'super content 2'
},
{
image: '../img/image-3.png',
title: 'title3',
content: 'blablablablbalbalbabla blablaba'
},
]
valuesCards.map(card=> {
var cardDiv = document.createElement('div');
cardDiv.innerHTML = `
<div class="product-header">
<img src="${card.image}"/>
</div>
<div class="product-content">
<h4>${card.title}</h4>
<p>${card.content}</p>
</div>
<button class="info-button">+ info</button>`
document.getElementsByClassName('products-cards')[0].appendChild(cardDiv);
})
<div id="products-cards-container">
<div class="products-cards">
</div>
</div>
You need to do a "for loop" that iterates over your valuesCards object and for each value return an html template an inject into the desired element in DOM.
For example:
// Define the object
const valuesCards = [
{
'image': '../img/image1.png',
'title': 'title 1',
'content': 'super content 1',
},
{
'image': '../img/image2.png',
'title': 'title 2',
'content': 'super content 2'
},
{
'image': '../img/image-3.png',
'title': 'title3',
'content': 'blablablablbalbalbabla blablaba'
}
]
// Identify the DOM element to store cards
cardsContainer = document.querySelector('#products-cards-container');
// Create a loop that iterates over valuesCards object
for (let value of Object.values(valuesCards)) {
console.log(value.title);
// Create an element to store new card content
let newCard = document.createElement('DIV');
// Add products-cards class to new element
newCard.classList.add('products-cards');
// Create a multiline string template with current values each time
cardHtml = `
<div class="">
<div class="product-header">
<img src="${value.image}"/>
</div>
<div class="product-content">
<h4>${value.title}</h4>
<p>${value.content}</p>
</div>
<button class="info-button">+ info</button>
</div>
`;
// Append the new element to the cardsContainer element in DOM
cardsContainer.appendChild(newCard);
// Inject the template html on DOM's new append item
newCard.innerHTML = cardHtml;
}
Important!! create a div element with the id="products-cards-container" in the html where you want to print the cards.
When I place a dynamically populated multiselect in a dropdown overlay, the multiselect's dropdown does not display when clicked. The exact same multiselect works just fine when it's not in a dropdown. See a fiddle that reproduces the issue here http://jsfiddle.net/yhnukfsz/6/ (started with the answer to this question).
The broken multiselect in question:
<div class="btn-group">
<button type="button" id="dropBtn" class="btn btn-primary btn-lg dropdown-toggle" data-toggle="dropdown">
Dropdown <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li>
<form>
<select class="form-control" id="mult2" multiple="multiple">
</select>
<button>
foobar
</button>
</form>
</li>
</ul>
</div>
And the JS:
$('.dropdown-menu').on('click', function(event) {
event.stopPropagation();
});
$('.selectpicker').selectpicker({
container: 'body'
});
$('body').on('click', function(event) {
var target = $(event.target);
if (target.parents('.bootstrap-select').length) {
event.stopPropagation();
$('.bootstrap-select.open').removeClass('open');
}
});
setUpMultiselect('#mult1');
setUpMultiselect('#mult2');
function setUpMultiselect(id) {
$(id).multiselect({
enableFiltering: true,
includeFilterClearBtn:false,
enableCaseInsensitiveFiltering: true,
selectAllJustVisible : true,
includeSelectAllOption : true,
nonSelectedText:"Filter ...",
numberDisplayed : 1
});
const options = [
{
title: 'title1', label: 'label1', id: 'id1', selected: true,
},{
title: 'title2', label: 'label2', id: 'id2', selected: true,
},{
title: 'title3', label: 'label3', id: 'id3', selected: true,
}]
$(id).multiselect('dataprovider', options);
$(id).multiselect('rebuild');
}
$('#dropBtn').click(() => {
setTimeout(() => {
setUpMultiselect('#mult1');
setUpMultiselect('#mult2');
}, 500)
})
Additional things I've tried that haven't fixed the issue include rebuilding/reinitializing the multiselect on the dropdown click event with and without a delay.
I create add-to-cart app.
Want to click each item and add it to cart.
But firstly I need to click button 'add to cart' and increase its value with every click.
As I added ng-repeat, I don't know how to write a function that will be responsible for adding separate item.
angular.module('TransactionApp', [])
.controller('TransactionsCtrl', function($scope) {
$scope.title = 'Online-store';
$scope.itemsArray = [
{ price: 50, name: "Whey protein", img: 'img/item-1.png', quantity: 0},
{ price: 60, name: "Protein bar", img: 'img/item-2.png', quantity: 0 },
{ price: 35, name: "BCAA", img: 'img/item-3.png', quantity: 0 },
{ price: 50, name: "Whey protein", img: 'img/item-1.png', quantity: 0 },
{ price: 60, name: "Protein bar", img: 'img/item-2.png', quantity: 0 },
{ price: 80, name: "BCAA", img: 'img/item-3.png', quantity: 0 }
];
// $scope.count = 0;
$scope.addTo = function(){
}
});
here is html:
<h2 class="title">{{title}} <i class="em em-shopping_bags"></i></h2>
<div class="container">
<div class="row">
<div class="col-lg-4 col-md-2 col-sm-6">
<div class="card" style="width: 18rem;" ng-repeat='item in itemsArray'>
<img class="card-img-top" ng-src={{item.img}} alt="Card image cap">
<div class="card-body">
<h5 class="card-title"></h5>
<p class="card-text">{{item.name}}</p>
<p class="price">{{ item.price | currency }}</p>
<i class="em em-shopping_trolley"></i> Add to cart <span class="number">{{ item.quantity }}</span>
</p>
</div>
</div>
</div>
</div>
</div>
Pass the item to controller with addTo(item):
<a href="#" class="btn btn-warning" ng-click="addTo(item)">
<i class="em em-shopping_trolley"></i>
Add to cart
<span class="number">{{ item.quantity }}</span>
</a>
after your addTo accepts a parameter:
$scope.addTo = function(item){ // 'item' is a reference to an element in itemsArray
item.quantity++;
}
I believe each of your item in view has its own Add to Cart Button against it and I also believe you want to increase the quantity property of each of the item each time a user clicks the button against that item.
For that all you have to do is pass the item to addTo() method like :-
<i class="em em-shopping_trolley"></i> Add to cart <span class="number">{{ item.quantity }}</span>
and modify the method definition in controller
$scope.addTo = function(var item){
item.quantity++;
}
here is the plunkr which will best illustrate my problem.
https://plnkr.co/edit/VrT7TmK6tY2u4k2NYJ2U?p=preview
there are two panels the panel on the left has a list of items that you can drag and drop onto wells on the right. the wells are created with a ng repeat. unfortunately I can not drag from one well to the another well on the right side of the screen. not sure why.
<div ng-controller="oneCtrl"><!--one-->
<div class="span3" style='margin-left:10px;'>
<div class="thumbnail"
data-drop="true"
ng-model='list1'
data-jqyoui-options="optionsList1"
jqyoui-droppable="{multiple:true}">
<div class="alert alert-info btn-draggable"
ng-repeat="item in list1"
ng-show="item.title" data-drag="{{item.drag}}"
data-jqyoui-options="{revert: 'invalid'}"
ng-model="list1" jqyoui-draggable="{index: {{$index}},animate:true}"
><!--alert-->
{{item.title}}
</div><!--alert-->
</div>
</div>
<div class="span3" style='margin-left:150px;'>
<div class=thumbnail>
<div class="well"
ng-repeat = "org in orgs"
data-drop="true"
ng-model="org.list"
data-jqyoui-options="{accept:'.btn-draggable:not([ng-model=org.list])'}"
jqyoui-droppable="{multiple:true}">
<div class=" alert alert-success btn-draggable" ng-repeat="item in org.list"
ng-show="item.title"
data-drag="{{item.drag}}"
data-jqyoui-options="{revert: 'invalid'}"
ng-model="org.list"
jqyoui-draggable="{index: {{$index}},animate:true}">
{{item.title}}
</div>
</div>
</div>
</div>
</div><!--one-->
and the javascript
var App = angular.module('drag-and-drop', ['ngDragDrop']);
App.controller('oneCtrl', function($scope, $timeout) {
$scope.orgs = [
{name: 'org1', list: []},
{name: 'org2', list: []},
{name: 'org3', list: []},
]
$scope.list1 = [
{ 'title': 'Item 1', 'drag': true },
{ 'title': 'Item 2', 'drag': true },
{ 'title': 'Item 3', 'drag': true },
{ 'title': 'Item 4', 'drag': true },
{ 'title': 'Item 5', 'drag': true },
{ 'title': 'Item 6', 'drag': true },
{ 'title': 'Item 7', 'drag': true },
{ 'title': 'Item 8', 'drag': true }
];
});
That's because you have data-jqyoui-options="{accept:'.btn-draggable:not([ng-model=org.list])'}" for the repeater in the right panel. This selector is the same for all the generated droppable-zones and it controls which draggable elements are accepted by the droppable. You will be able to drag and drop the items between the generated zones, if you will remove this option (or modify it according to your requirements).
Working plnkr.
In my UI Grid here are the Column Defs in my myController.js file:
{ field: 'trans_typ_dsc', headerTooltip: 'Transaction Type Description', displayName: 'Transaction Type Description', cellTemplate: '<div class="wordwrap">{{COL_FIELD}}</div>' },
{ field: 'trans_stat', displayName: 'Transaction Status' },
{ field: 'sub_trans_actn_typ', displayName: 'Sub Transaction Action Type', cellTemplate: '<div class="wordwrap">{{COL_FIELD}}</div>' , visible : false },
{ field: 'case_key', displayName: 'Case Key', visible: true, celltemplate: '<a class="text-center" ng-href="#" ng-click="grid.appScope.setAssociateCaseModal(row)">{{COL_FIELD}}</a>' },
{ field: 'approved_by', displayName: 'Approved By', visible: false }
Here on clicking the case_key link a UI Bootstrap modal should pop up .
How to do that ?
I know in a html file using a button click it is something like :
<h3>Search Transaction</h3>
<div style="float: right; margin-top: -35px"><button type="button" class="btn btn-default" data-toggle="modal" data-target="#recentSearchesModal">Recent Searches</button></div>
</div>
<div class="modal fade" id="recentSearchesModal" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Recent Searches</h4>
</div>
<div class="modal-body">
<div class="panel panel-default">
<div class="menu_simple" ng-repeat="obj in CaseRecentSearches" style="padding:8px;">
<ul>
<li>
{{obj | placeholderfunc}}
</li>
</ul>
</div>
<!-- /.panel-body -->
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
But here the click event is my controller.js file then how to get the modal opened ?
You need to modify the field's cellTemplate and then call grid.appScope.openModal(). openModal should live in your main controller under $scope.openModal. Do it like this:
Your template:
var myTemplate = "<a href='#' ng-click='grid.appScope.openModal($event, row)'>{{ row.entity.myFieldName }}</a>";
Use the template in gridOptions.
$scope.gridOptions = {
columnDefs: [{
field: 'myFieldName',
displayName: 'My Field Name',
cellTemplate: myTemplate;
}]
};
Function to call modal:
$scope.openModal = function (e, row) {
//in here, you can access the event object and row object
var myEvent = e;
var myRow = row;
//this is how you open a modal
var modalInstance = $uibModal.open({
templateUrl: '/path/to/modalTemplate.html',
controller: MyModalCtrl,
backdrop: 'static'
//disable the keyboard
//keyboard: false,
resolve {
//pass variables to the MyModalCtrl here
event: function() { return myEvent; },
row: function() { return myRow; }
}
});
//call the modal to open, then decide what to do with the promise
modalInstance.result.then(function() {
//blah blah the user clicked okay
},function(){
//blah blah the user clicked cancel
})
}