MeteorJS Packery layout has overlapping items when redrawn - javascript

I am new to coding and new to Meteor so have made my fair share of blunders along the way - so far I've managed to fix them but this one's got me well and truly stumped.
I'm using packery to layout some divs containing information on projects that contain a number of divs with information on tasks within each project. So far so good, the layout works nicely when the template first loads.
When I add a new task to one of the projects, which gets added to the Tasks collection, the layout redraws but that project, which is now 1 row longer, overlaps the next project down the layout.
I've re-used the answer from here (MeteorJS and Packery layout doesn't re-render when collection is updated) but this doesn't work for the redraw.
projects.html:
<template name="projects">
<div class='grid' id='allProjects'>
{{#each project}}
<div class='grid-item' id='project'>
<div project content goes in here>
</div>
{{#each task}}
<div id='task'>
<div task content goes in here>
</div>
</div>
{{/each}}
</div>
{{/each}}
</div>
</template>
projects.js:
Template.projects.onRendered(function(){
this.find('.grid')._uihooks = {
insertElement: function(node, next){
triggerPackeryLayout();
$('.grid').append(node);
$('.grid').packery('appended', node);
}
};
});
function triggerPackeryLayout(){
var $grid = $('.grid');
$grid.packery({
itemSelector: '.grid-item'
});
}
I think it's something to do with timing of when the layout is redrawn because when I add another task to the project, which uses a modal window, the layout corrects itself as the modal opens.
Do I need to delay the layout to allow the new Tasks item to load from the collection?

Related

How do I create a grid system using handlebars in Meteor.js?

I'm trying to build a simple memory card game in Meteor and I can't seem to create a grid of my cards to populate in html. I'm just trying to get a 4x4 grid for right now.
Here is the javascript:
Template.body.helpers({
cards: function() {
var allCards = Deck.find({}).fetch();
var chunks = [];
while (allCards.length > 0) {
chunks.push(allCards.slice(0, 4));
allCards = allCards.slice(4);
}
return chunks;
},
});
And here is the HTML:
<body>
<div class="container">
<div name="gameBoard">
{{#each cards}}
{{> cardsRow}}
{{/each}}
</div>
</div>
</body>
<template name="cardsRow">
<div class="row">
{{#each row}}
{{> card}}
{{/each}}
</div>
</template>
<template name="card">
<span class="text">{{text}}</span>
</template>
Right now I just have simple text entries in the db to see what I'm doing before I pull in images. I've tried console logging from my JS and I believe I'm creating the array of spliced rows correctly so I think the problem may be in the way I have arranged the markdown.
I tried pulling the each cards loop into a template as well instead of inside the body but I'm not sure how to render templates on demand. This is potentially an option since I have a new game button event listener that could call a render. I'm just not sure how to explicitly render in Meteor.
I tried following this previous post but I couldn't get it to work:
How do I populate a bootstrap grid system using handlebars for each command in Meteor.js?
Thoughts? I can provide more of my code base if needed.
Neither row in {{#each row}} in the "cardsRow" template, nor {{text}} in the "cards" template, refer the way that you hope they do. You need to define row and text as template helpers for each of these templates. In a template helper, this refers to the data object associated with the template.
In your case, when you iterate through #each cards in "container", this is passed into the "cardsRow" template as one of the chunks defined in your cards helper function. The helpers below should illustrate this, and are sufficient for your example.
Template.cardsRow.helpers({
row: function() {
console.log(this); // a chunk of cards
return this;
}
});
Template.card.helpers({
text: function() {
console.log(this); // a number in a chunk
return this;
}
});

Semantic UI Meteor modal initalization

I'm running Meteor with Semantic UI as a framework .
I've got my main page on which I load X detail cards who all come from the same data source. All the detail cards have buttons, for example trash to remove the card.
I'm confirming actions on the buttons through modals.
I've got all of my modals in a separate template called modals.
From my main page I load my modals:
{{>modals}}
Inside my modals template I've got:
<template name="modals">
<div id="takeModal" class="ui modal">
{{#with data}}
<div class="ui header">
//HEADER
</div>
<div class="ui content">
// DATA USAGE IN TEMPLATE
{{city}}</td>
</div>
</div>
</template>
Above example is commented with // and just a fraction of the real thing.
The problem I'm running into is that I'm using the buttons on said card to call for the modal. The button eventhandler looks like:
Template.availablCard.events({
'click #checkmark': function () {
Session.set('data', this);
$('#takeModal').modal('show');
}
....
and the modal template has a helper:
Template.modals.helpers({
data: function () {
return Session.get('data');
}});
The problem I am facing is that the modals never function properly the first time because a click hasn't been registered yet and Session.data hasn't been set yet.
Is there a way to initialize the modals so they get loaded into the DOM, but still give them a data context?
ps. I've chosen this approach so I don't have to give every card it's own modal.

Extend mobile view in Kendo UI Mobile?

It doesn't seem possible to extend the view for mobile. I would like to do so because I can predefine some options and behavior. I have create a sample here illustrating the problem, which gives me an error of:
Your kendo mobile application element does not contain any direct child elements with data-role="view" attribute set. Make sure that you instantiate the mobile application using the correct container.
JavaScript:
kendo.mobile.ui.plugin(kendo.mobile.ui.View.extend({
init: function (element, options) {
kendo.mobile.ui.View.fn.init.call(this, element, options);
},
options: {
name: 'ViewCustom'
}
}));
$(function () {
new kendo.mobile.Application(document.body);
});
HTML:
<section data-role="layout" data-id="default">
<header data-role="header">
<div data-role="navbar">My App</div>
</header>
<footer data-role="footer">
<div data-role="tabstrip">
Home
</div>
</footer>
</section>
<div id="home" data-role="viewcustom" data-layout="default">
Welcome to the home page!
</div>
http://jsfiddle.net/basememara/67RZN/
Kendo support simply said it's not supported - the mobile application does not recognize the descendants and does not initialize them upon start. This is a huge extensibility roadblock for mobile, so I've been poking around the source code to see where this is hard coded and I think the change will be somewhere in ViewEngine in kendo.mobile.view, possibly in _hideViews. I also see some hard coded views in kendo.mobile.pane. So I think this will be a big hack of the source code to get it working.
My question is there a way to extend the view without creating a new class, such as using prototype to extend kendo.mobile.view? Any help, experience, or insight will be greatly appreciated!
Instead of relying on Kendo to find the initial view to display, which will search specifically for data-role="view" you can instead programmatically tell it the initial view:
new kendo.mobile.Application(document.body, {
initial: "home"
});
I updated your example (and clicking the "Home" button also navigates to a second view just to make sure that worked as well).

Ember.js outlets and routes

I've been trying to learn Ember.js for the last two weeks and I've really struggled. I'm hoping for an 'a-ha' moment but each new feature I try to implement always results in hours of failed testing. I just don't seem to be grasping the framework. I feel like I'm working against it. I'm hoping someone can explain a path forward through this simple example.
I am creating a web app that allows the user to pick products that they will sell to a client. There is a list of products they can chose from and then a list of products they've selected.
I imagine a left-column with navigation controls and a main column showing either the selected products or new products they can add to the order. Here is the basic template:
<script type="text/x-handlebars" data-template-name="pc">
<div id="nav">{{outlet nav}}</div>
<div id="main">{{outlet main}}</div>
</script>
Here is the left navigation template:
<script type="text/x-handlebars" data-template-name="nav">
<div class="button">{{#linkTo "pc.add"}}Add Products{{/linkTo}}</div>
</script>
Here is the selected products template:
<script type="text/x-handlebars" data-template-name="selectedProducts">
{{#each p in controller}}
<div class="product">
<h4>{{p.name}}</h4>
</div>
{{/each}}
</script>
Here is the available products template:
<script type="text/x-handlebars" data-template-name="addProducts">
<div id="addProducts" class="addProducts">
{{#each p in controller}}
<div class="product">
<h4>{{p.name}}</h4>
</div>
{{/each}}
<button {{action "addSelectedProducts"}}>Add Selected Products</button>
<button {{action "back"}}>Back</button>
</div>
</script>
I can load the 'pc' template with some already selected products. Great. I can also navigate to the 'Add Products' template. Great. But when I click 'Add Selected Products', I can't figure out how to move the selected products into the controller/model behind the 'Selected Products' template and then get that template to re-render in place of the 'Add Products template'. It's really two question. How do I update the model of another controller from within a different controller? And, how do I then transition from an event to another route?
Can someone show me how you would design the Route(s) and Controllers? I know that's asking a lot. I"m mostly interested in seeing how you respond to an event in the AppProductsController, update SelectedProductsController's model, and then transition to SelectedProductsRoute and have it re-render the template.
I want to believe this is an amazing framework but I just keep hitting walls.
Andrew
How do I update the model of another controller from within a different controller?
Connect controllers using the needs property. So something like:
//in AddProductsController
needs: ['selectedProducts']
addSelectedProducts: function() {
// Now selectedProductsController can be accessed via the controllers property
otherController = this.get('controllers.selectedProducts');
// add the selected ones...
}
See http://emberjs.com/guides/controllers/dependencies-between-controllers/
how do I then transition from an event to another route?
//in AddProductsController
this.transitionToRoute('blogPosts');
See http://emberjs.com/api/classes/Ember.Controller.html#method_transitionToRoute

viewContentLoaded - Without duplicating code per each controller - AngularJS

Hey all I'm trying to get a feel for angular and have ran into a little snag.
I have a container structure like the following:
<div class="main-container" ng-view>
<!-- The below divs are constantly being
reloaded based on the current URL and it's associated view -->
<div class="left-col">
</div>
<div class="right-col">
</div>
</div>
Before I implemented Angular I just had a simple script that would check the height of the window and set the height of the left column and right column divs accordingly.
With angular there is probably a better way to do this then attaching an event function to the window object. Basically I want to fire a function everytime a new view is rendered but not duplicate the below code in all of my angular controllers like so:
$scope.$on('$viewContentLoaded', setColumnHeight);
Any help would be appreciated. Thanks!
I've solved this problem in my app by having a root "Application Controller" at the top of the DOM tree. For example:
<body ng-controller='applicationController'>
...
<div class="ng-view"></div>
...
</body>
applicationController is always there, and can set up bindings on its scope when it is created.
How about putting that event listener on the root scope:
$rootScope.$on('$viewContentLoaded', setColumnHeight);
You could use something like this:
<div class="main-container" ng-view>
{{ setColumnHeight() }}
<!-- The below divs are constantly being
reloaded based on the current URL and it's associated view -->
<div class="left-col">
</div>
<div class="right-col">
</div>
</div>
and it will check the height every time a render is made, however, this seems to be a bit over processing.
The best approach would be to only update the height from both columns when the height of one of them changes. For that you could use DOM Mutation Observers, however they are not yet available on all browsers. If that's not a problem for you, check the mutation-summary lib.
If you are using jQuery you can also try this: https://github.com/jqui-dot-net/jQuery-mutate (examples here).

Categories

Resources