How do I structure a Timezone Checking App in Ember - javascript

As a way to learn Ember, I'm trying to build a simple app, now without the crutches of a tutorial.
The app will do the following --
User writes his own city
User writes the city of person he wants to meet
Function will spit back up all the times that are mutually good for eachother. I.e times where neither of them will have to wake up too early to stay too late)
I'm a bit confused as to how to structure the data the Ember way. How would I go about it?
I'm thinking --
There will be an index.handlebars
- This will have the 2 input fields for both person A and person B's cities
- This will be backed by the 'Meeting' Model(attributes : cityA, cityB)
When the submit button is clicked, this is where I get confused --
I can imagine that there is a model called MeetingTime (with personA's time, and personB's time).
In what way would I present that, following Ember's best practices? What routes, controllers, templates etc?
Currently, this is what I have ->
RightTime.Router.reopen({
location: 'history'
});
RightTime.Meeting = DS.Model.extend({
myCity: DS.attr('string'),
theirCity: DS.attr('string'),
meetingTimes: function() {
if (myCity && theirCity) {
// get back a collection of meeting times
}
return false;
}.property('myCity','theirCity')
});
RightTime.IndexRoute = Ember.Route.extend({
model: function() {
//return this.store.createRecord('meeting');
//the above return is giving the error 'unedfined is not a function'
}
});
#index.handlebars
<div class="container">
<div class="col-md-6 col-md-offset-3 col-lg-4 col-lg-offset-4">
<header class="animated fadeInDown">
<h1><span class="twenty-four-header">24</span>Time</h1>
<h3>Get Great Meeting Times Instantly</h3>
</header>
<section class="main-options animated fadeInDown">
<div class="form-group">
{{input value=myCity placeholder="What's your city?" class="form-control input-lg"}}
</div>
<div class="form-group">
{{input value=theirCity placeholder="What their city?" class="form-control input-lg"}}
</div>
<div class="form-group">
<button {{action 'getTimes'}} class="btn btn-lg get-times btn-block btn-primary">Get Times!</button>
</div>
</section>
</div>
</div>

Ended up making it! www.24time.co
The code can be found at www.github.com/stopachka/right-time
There's one model called Meeting.
A person chooses a city by interacting with the Places Autocomplete API. When they choose, it returns latLng positions, which are attached to the meeting. As soon as the model has both positions for the cities, it makes an ajax request to /api/meeting, sending the location parameters.
The API returns back all the best times. I'm pretty sure I'm not doing it the ember way though, perhaps the model can be broken down differently, and the times can be models themselves.

Related

EmberJS template component suddenly not rendering on page

I'm following this Ember tutorial and I've suddenly run into an issue where my rental-listing.hbs template component stops rendering. It started when I began implementing the map service.
I don't understand where this could be happening. I've copied the code from parts of the GitHub repository that I thought were relevant but to no avail.
I have a rental.hbs template that looks like so:
<div class="jumbo">
<div class="right tomster"></div>
<h2>Welcome!</h2>
<p>We hope you find exactly what you're looking for in a place to stay.</p>
{{#link-to "about" class="button"}}
About Us
{{/link-to}}
</div>
{{outlet}}
Which in turn has a template component called rental-listing.hbs:
<article class="listing">
<a
onclick={{action "toggleImageSize"}}
class="image {{if this.isWide "wide"}}"
role="button"
>
<img src={{this.rental.image}} alt="">
<small>View Larger</small>
</a>
<div class="details">
<h3>{{link-to this.rental.title "rentals.show" this.rental class=this.rental.id}}</h3>
<div class="detail owner">
<span>Owner:</span> {{this.rental.owner}}
</div>
<div class="detail type">
<span>Type:</span> {{rental-property-type this.rental.category}} - {{this.rental.category}}
</div>
<div class="detail location">
<span>Location:</span> {{this.rental.city}}
</div>
<div class="detail bedrooms">
<span>Number of bedrooms:</span> {{this.rental.bedrooms}}
</div>
</div>
<LocationMap #location={{this.rental.city}}/>
</article>
The only thing I have added to the above is the line <LocationMap #location={{this.rental.city}}/> but it still doesn't work if I remove it.
The console shows me no errors and I can actually see I am getting the three dummy objects I want from Mirage:
So I'm definitely getting the objects and from what I see I'm doing everything necessary in the templates to render it but they aren't. Should I be looking somewhere else?
Are you able to provide a link to your example? By having each piece of the ember application you mention it would be best to answer definitely. I can give a general answer with strategies for debugging the template.
The conventions behind ember.js make understanding the "whys" frustrating at first and possibly opaque. Ember's handlebars implementation governs how values are populated and accessed within templates using very specific rules. Ember treats templates (handlebars files) differently depending on whether it is for a route or component. Component's have an isolated context and must receive values by explicit passing in or dependency injection. Then, you can use such values in a component's template by accessing those properties with {{this.somePassedInValue}}.
In the super-rentals app, it appears the rental index route invokes the components responsible for displaying the individual units. I found this in app/templates/rentals/index.hbs.
<li><RentalListing #rental={{rentalUnit}} /></li>
The route template iterates over the list of filteredResults. Each of these is the rentalUnit. A good first step would be to use the {{log}} helper to print out that the value of rentalUnit to ensure it is what you expect.
Alternatively, you could try cloning https://github.com/ember-learn/super-rentals and applying the changes you want to make step by step from the master branch. By doing so, you could easily undo a single change to see what caused something to not show up as expected.
<LocationMap #location={{this.rental.city}}/>
to be written as below
<LocationMap #location={{this.rentals.city}}/>
may be typo error.
also repeat this for there place in that template.
Because the model name in the console is rentals not rental

ng filtering using scope defined in controller

I am developing a webpage using angular js. and i want to add some filter to the site,
here is my HTML code
<div ng-repeat="data in datas | filter:{area:course} | filter:{subject:subFilter} | filter:{city:cityFilter}">
<h5><span class="text-warning">#</span> {{data.intrest}}</h5>
<div class="row">
<div class="col-xs-3">
<h5 class="text-info">Name</h5>
<p>{{data.name}}</p>
</div>
<div class="col-xs-3">
<h5 class="text-info">Subject</h5>
<p>{{data.subject}}</p>
</div>
<div class="col-xs-3">
<h5 class="text-info">Address</h5>
<p>{{data.city}}, {{data.state}}</p>
</div>
<div class="col-xs-3">
<button class="btn btn-warning" style="margin-top:10px;">View</button>
</div>
</div>
<hr>
</div>
And this is my controller file
app.controller('mainController',['$scope','$http','$routeParams',function($scope,$http,$routeParams){
$http.get('assets/newtab.json').success(function(data){
$scope.department=data;
$scope.whichItem=$routeParams.itemId;
$scope.course=$scope.department[$scope.whichItem].course;
});
$http.get('assets/engineering.json').success(function(data){
$scope.datas=data;
$scope.whichItem=$routeParams.itemId;
$scope.optItem=[
{title:"Random",value:" "},
{title:"Question Paper Setting",value:"Question Paper Setting"},
{title:"Question Paper Passing Board",value:"Question Paper Passing Board"},
{title:"Question Paper Post Auditing",value:"Question Paper Post Auditing"},
{title:"Question Paper Evaluation",value:"Question Paper Evaluation"},
{title:"Member for board of study",value:"Member for board of study"},
{title:"Member for academic council",value:"Member for academic council"},
{title:"Result passing board",value:"Result passing board"},
{title:"Invigilation",value:"Invigilation"},
{title:"Door Valuation",value:"Door Valuation"},
{title:"Exam squad",value:"Exam squad"}
];
});
}]);
here goes the snippet from engineering.json and newtab.json
enginering.json
[{"id":"1","name":"Sam","dob":"","age":"21","gender":"","department":"16\/03\/1995","area":"Nuclear Medicine Technology Course","institution":"Park College of Technology ","city":"Tiruppur","state":"Tamil Nadu","intrest":"Question paper evaluation","mobile":"","email":"jaya5292.jmj#gmail.com","password":"jaya","subject":"Computer Networks"},{"id":"2","name":"jaya","dob":"","age":"21","gender":"","department":"16\/03\/1995","area":"Nuclear Medicine Technology Course","institution":"Park College of Technology ","city":"","state":"","intrest":"","mobile":"","email":"jaya5292.jmj#gmail.com","password":"jaya","subject":""},{"id":"3","name":"jaya","dob":"","age":"21","gender":"","department":"16\/03\/1995","area":"Nuclear Medicine Technology Course","institution":"Park College of Technology ","city":"","state":"","intrest":"","mobile":"","email":"jaya5292.jmj#gmail.com","password":"jjjj","subject":""}]
newtab.json
[{"Department":"Arts","course":"B.A. English"}, {"Department":"Arts","course":"B.A. English (Computer Applications)"}, {"Department":"Arts","course":"B.A. Economics"}, {"Department":"Arts","course":"B.A. History"}, {"Department":"Arts","course":"B.A. Political Science"}, {"Department":"Arts","course":" B.A. Tamil "}, {"Department":"Arts","course":"B.Lit. Tamil "}]
in my controller on line 5 i've fetched the value on clicked item and stored it in a variable named "course", i must be able to filter the result in my html using this "course". i wrote a syntax in my html file. but it is not filtering the proper result
From what I'm seeing, the .area property for datas (enginering.json) does not overlap the .course property of newtab. For each of the engineering.json, the area is "Nuclear Medicine Technology Course", so no matter what department you pick from newtab, there will be no match.
Working Fiddle here. In this fiddle, I've changed to .area of Sam to show that the filter works (and removed the additional filters for simplicity, though they should work fine).
But another possible problem is that the data returned from $http is usually accessed in the form
$http.get(url).then(function(result) {
$scope.variable = result.data;
}
because the object returned from the $http call has the data in the .data property. So that's something to look at, too.
EDIT: As pointed out by #mzulch below, your $http syntax is correct for angular versions below 1.5

Meteor publish and subscribe not working

I have a fairly novice question and am hoping someone can help me.
I have the following code in which subscribe/publish is not working:
if (Meteor.isServer) {
Meteor.publish('items', function () {
return Items.find({});
});
}
if (Meteor.isClient) {
Meteor.subscribe("items");
}
In my template:
<template name="items">
<div class="ui segment">
<div class="ui relaxed list">
{{#each item in items}}
<div class="item">
<img class="ui avatar image" src="http://placehold.it/20x20">
<div class="content">
<a class="header">{{item.text}}
</div>
<button class="delete">×</button>
</div>
{{/each}}
</div>
</div>
</template>
But nothing gets output. However when I add:
Template.items.helpers({
items: function () {
return Items.find({});
}
});
I do see the list properly. Why is this so? Also I am clearly confused as to why someone would want to use subscribe/publish along with the template helpers.
I suggest you read Data flow from the database to the UI: Three layers of Meteor
You are creating a publication labeled: items. Then you are subscribing to a publication labeled deals. This will not work as the labels must match for the subscription to work.
If adding that template helper then shows the data in the UI, you must have the autopublish package in your app. It will be autopublish, not your pub/sub, that is sending the client the data the client puts in it's mini-mongo Items collection.
So pub/sub gets the data from the server to the client, but doesn't display it. That is why you need the template helper, to get the data from the client's mini-mongo collection into the format the templates require.
You must subscribe() using the same name as used in the publish(). In your case (pay attention to 'items'):
/server:
Meteor.publish('items', function () {
return Items.find({});
});
/client:
if (Meteor.isClient) {
Meteor.subscribe('items');
}
The publish/subscribe link is telling meteor to send all docs in the 'Items' collection to minimongo on the client. Now, the purpose of the template helper is to tell meteor that you want to reactively update the template any time a document changes in Items.
A good reference on the subject: https://www.discovermeteor.com/blog/understanding-meteor-publications-and-subscriptions/

AngularJS ng-repeat nested form w/ socket.io

I am building a real time application with socket.io. I've ran across a problem using ng-repeat with a nested form inside an ng-repeat tag. Here is the jist of the code:
<div class="row" id="thingArea">
<div class="thing text-center col-sm-{{12/bigObject.columns.length}} col-xs-{{12/bigObject.columns.length}}" ng-repeat="column in bigObject.columns" data-columnindex="{{$index}}" id="column{{$index}}">
<h3 class="title">
<span class="text header-text"><font size="7" ng-bind-html="column.title"></font> </span>
</h3>
<form ng-submit="addRow($index, rowValue)" class="thing-form" >
<div class="form-group">
<input type="text" class="form-control" ng-model="rowValue" placeholder="{{column.placeholder}}">
<br/>
<br/>
<div class="thing-column" as-sortable="thingSortOptions" ng-model="column.rows">
<div class="alert alert-{{column.color}} alert-dismissible" role="alert" ng-model='row' ng-repeat="row in column.rows" as-sortable-item>
<div as-sortable-item-handle>
<button type="button" class="close" ng-click="deleteRow(column, row)" aria-label="Close"><span aria-hidden="true">×</span></button>
{{row.value}}
</div>
</div>
</div>
</div>
</form>
</div>
</div><!--//row-->
The schema of bigObject is as follows:
var RowSchema = new Schema({
value: String
});
var ColumnSchema = new Schema({
title: String,
placeholder: String,
color: String,
selected: String,
rows: [RowSchema]
});
var BigObjectSchema = new Schema({
_id: {
type: String,
unique: true,
'default': shortid.generate
},
name: String,
startTime: Date,
endTime: Date,
columns: [ColumnSchema],
info: String,
active: Boolean
});
Basically bigObject can have N columns, with N rows inside of it. This is where I'm using ng-repeat to first iterate over the columns, which contains a form with an input to add rows. Then within the column I then iterate over the rows.
Okay. Here's the my problem. Since I'm using socket.io to sync real time bigObject updates between clients when the bigObject changes it re renders ALL of the ng-repeat's...and in dosing so blows away the input. As in, if one client is typing in an input, and another client causes an update, the user receiving the update page re renders and whatever they are type gets blown away.
My thoughts so far:
Take the input box out of all the ng-repeat tags, so its unaffected from updates. This adds complexity however, again I could have N columns...means N input boxes. It's nice having them correlate.
Ditch the idea of being completely dynamic in terms of N columns since in reality the UI with be fixed to only allow 2-3 columns. But ya, that seems lame.
Find some fancy angular/css tricks to hack around this....which haven't been super fruitful
Am I approaching this all wrong? I usually favor the simplest option..the first option adds code complexity, and the second adds code duplication but more simple.
Thanks.
You could change it like this:
<div....ng-repeat="column in bigObject.columns" ng-init="columnIndex = $index"....>
Replace ng-model="rowValue" to something like ng-model="temp[columnIndex].rowValue" , where temp is another object in your model, unrelated to BigObject. This way your temporary (not yet saved data, and available to only the current client) is in a different place than the one available to all clients, and the update of BigObject shouldn't interfere with the text in your input.
Edit:
Not sure if I was clear enough(or if it's the recommended way to do it), but temp should be on the model, not only on the scope(since the scope gets replaced and it loses the content)

Create sub controller without route in Ember.js

I'm building a chat app with ember.js(I'm very new to it) that has the following specifics:
Every user have multiple threads each one with only two users involved
I need to display the thread and the messages in a "facebook" manner with the list of threads aside and the messages right of it
Every message have a read state that I need to work with
The app works with an url pattern like /:thread_id
Giving theese, I've already setted up an app
https://gist.github.com/Fed03/33da4a7c28c792af23cf (I've merged the various js file for sake of your readability) but the problem rises on the specific message state.
From what I understand about ember, evrything "needs" a route in order to proxy things, but if you look at the code and at the specifics a don't need a message route but I'd need a MessageController to manage the single message states.
Obviously I'm doing something very wrong with the architecture of this app, so if someone cuold give me some advices would be great!
Thank you in advance!
You'll want to use a {{render}} helper.
Instead of rendering each model in the threads template, pass the model to a {{render}} and have it handle displaying the message and it'll have it's own controller.
You'll need to create a seperate template for the msg, like this:
<script type="text/x-handlebars" data-template-name="message">
<div class="col-md-12">
<div class="well">
<div class="message-header">
<h5>{{user.fullname}}</h5>
</div>
{{body}}
{{isRead msg}}
</div>
</div>
</script>
And then change your thread template to this:
<script type="text/x-handlebars" data-template-name="thread">
{{#each msg in model.messages}}
{{render 'message' msg}}
{{/each}}
<div class="col-md-12">
<div class="row">
<div class="col-md-5">
{{textarea value=message rows="3" class="form-control" data-thread=model}}
<div>
<button class="btn btn-primary pull-right" {{action 'send' model}}>
Submit
</button>
</div>
</div>
</div>
</div>
</script>
Then each msg will have it's own instance of MessageController and you can use it to handle it's state.

Categories