EmberJS template component suddenly not rendering on page - javascript

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

Related

Angular : template changing depending on javascript value

I am building an angular app, with templates changing depending on with ngscope as seen on the samples below.
<label class="btn btn-default">
<input id="cacher" value="settings" type="radio" data-ng-model="user.status">Settings
</input>
</label>
and here i'm calling my html template userPageSettings
<div id="wrapper" ng-switch="user.status">
<div ng-switch-when="settings">
<user-page-settings></user-page-settings>
</div>
</div>
Trouble is, i'm trying to get access to the templates (and the correct route) through a dropdown in the navbar, which is supposed to do exactly the same thing as my normal menu. But if i simply call the templates from my navbar they will be shown on the current page, therefore at the incorrect route.
In my navbar code i'm doing the following, which is bringing me back to the correct route, but showing me my default template (aka home, not shown here, but called through the same method and has the number 6)
<li role="menuitem">Settings</li>
The number "1" (and the others using 2,3 etc) are hashed in my javascript and put into a variable. I would like to make my templates appear depending on those numbers.
Any ideas how ??
:) Thank you !!

angular.js: routing to an editor-version of the current article

I have some articles of the same category and I'm routing like this:
app.config(function($routeProvider) {
$routeProvider
.when('/chapter/:title', {
templateUrl: 'article.html',
controller: 'article'
});
});
article.html:
<h1>{{title}}</h1>
<p>{{content}}</p>
<button>Editor</button>
But now I want to get a route from every article of this chapter to an editor version to change the content. This editor-version could look like this:
editor_article.html:
<input type="text" value="{{title}}">
<textarea>{{content}}</textarea>
So what is the best way for routing the button of an article to the editor_article.html-template and load it with the same data?
There is no "best-way" here, and it all depends on your context.
Do all end-users have equal access to this (or put another way, should anybody who can open the dev-console be allowed to access this page)?
If not, you need to solve the login problem before you load most of the code for your SPA.
If login isn't a problem, or already taken care of, why do you need separate routes?
Do you need to cache these pages separately in-browser?
Are there other considerations beyond that?
Totally legitimate question; from an artistic perspective, perhaps you're hoping for page transitions which match other transitions you have for when you do change routes, or you are relying on routeParams for some logic that we don't know about.
But chances are good that all of the above things aside, you could simply have a button and a couple of ng-if statements, with directives.
<body >
<main ng-view></main>
</body>
<!-- template -->
<section >
<button
ng-click="article.toggleMode()">{{
article.editMode ? "View": "Edit"
}}</button>
<article-view
content="article.content"
ng-if="!article.editMode"
></article-view>
<article-edit
content="article.content"
onsave="article.save(content)"
ng-if="article.editMode"
></article-edit>
</section>
Using directives to define the two templates, using controllerAs:"article" in the example above.
Even that might be complicating it.

Data Binding Fails after app.setRoot('viewmodels/shell') for Durandal

On Durandal, I have a login page that's styled different from my other pages, so taking the advice I saw on some of the posts here, I've set up main.js to do a:
app.setRoot('viewmodels/login');
And on the login page, I provide the below method in login.js that resets the root:
loginRedirect: function() {
app.setRoot('viewmodels/shell');
}
The idea is that the user should go to the login page by default, and once logged in, I will invoke the method loginRedirect, which sets shell.html to be the root and thus reloads the content, and he should be able to navigate other pages from there.
Here's my login.html:
<div class="login">
<div data-bind="compose:'header-nav-plain.html'"></div>
<div class="container">
<!-- Content here-->
</div>
</div>
<div data-bind="compose:'viewmodels/footer'"></div>
<a class="go-inner-pages" data-bind="click: loginRedirect" href="#">Test link to go to 'inner' pages</a>
And here's my shell.html, that is the doorway to all other pages:
<div>
<div data-bind="compose:'viewmodels/header-nav'"></div>
<div class="container">
<div data-bind="compose:'viewmodels/site-nav'"></div>
<div data-bind="router"></div>
</div>
<div data-bind="compose:'viewmodels/footer'"></div>
</div>
You can see that shell.html is slightly different in structure from login.html, in that it binds to a different header-nav.html, and also a site-nav.html. (They share the same footer.html.) So on the login page, when I click on the test link that calls the loginRedirect method, it sets the root of the app to be shell.html, which will load the default page based on the parameters passed to router.map, as defined in shell.js:
activate: function(){
//Initializing router
router.map([
{ route: '', moduleId: 'viewmodels/dashboard', title: 'Dashboard', nav: true }
])
.buildNavigationModel();
//More code
return router.activate();
But, when I click on the test link and invoke loginRedirect, the new dashboard content is loaded, but the new header-nav and site-nav data binding didn't happen. I checked the inspector, and see that the structure has indeed changed to that of shell.html (as opposed to login.html), only data binding for header-nav and site-nav didn't happen. I.e. here's the new html after invoking loginRedirect:
<div>
<div data-bind="compose:'viewmodels/header-nav'"></div><!--header nav content not bound-->
<div class="container">
<div data-bind="compose:'viewmodels/site-nav'"></div><!--site nav content not bound-->
<div data-bind="router"><div class="durandal-wrapper" data-view="views/dashboard" data-active-view="true">
<!-- Dashboard content successfully loaded -->
</div><!--end data-bind="router"-->
</div><!--end .container-->
<div data-bind="compose:'viewmodels/footer'">
<!--footer content loaded-->
</div>
And from the Console (see below), one can see that while the shell and dashboard are bound, (even footer is bound a second time), header-nav and site-nav are not.
Does anyone have any idea why this is happening and what I might be doing wrong? Thanks in advance for your attention, hope to hear from someone soon. Cheers.
For view-only bindings, you would bind this way (we do the same as you, so I'm copying and pasting our code):
compose: {view: 'shellLeftFooter.html'}"
For views bound to viewModels, you bind this way:
compose: {model: 'viewmodels/navigation/shellNavigation'}
The default viewLocator will use the following convention:
If a view is specified with no model, then the view must be identified with the .html extension, as I have done in the former example, and it will not be bound to a viewModel;
If a model is specified with no view, as I have done in the latter example, then the model file is assumed to have a .js extension, and it is also assumed that a view exists in a folder named views under the app directory, with the same name as the model, but with an .html extension.
These aren't the only two conventions, but they are the ones germane to this discussion. To put the above in different words, make sure you have both a viewmodels and a views directory that are siblings of each other under the app directory. Make sure you give the viewModel and the view identical names, differing only in their extensions (.js for the former and .html for the latter).
I'm seeing all of your .html and .js files in the code you posted, so I'm sure what your intention is in each case (view only or model-view-viewModel). Also, your compose binding is not quite to standard.

One way binding + dynamic binding in AngularJS

I will start by explaining what we are trying to achieve.
We have just jumped on the Angular bandwagon and are building a prototype with it to see what it is capable of.
Currently there is a load of data (grades in this case) on the server and we display that data using Angular.
The following is the code we use:
<ul class="phones">
<li class="list-group-item" onclick="toggleExpandedView(this, true, 500)" ng-repeat="grade in grades | filter:query | orderBy:orderProp">
<span ng-show="grade.comment"><img src="../Content/images/comment.gif"/></span>
<a class="btn btn-primary editButton" style="float: right; position: absolute; right:10px;" ng-href="#/grades/{{grade.gradeId}}">Edit</a>
<div class="heading1"><a ng-href="{{grade.url}}" target="_blank">{{grade.gradeValue}}</a></div>
<div>Provided by {{grade.assessorFirstname}} {{grade.assessorLastname}} on {{grade.dateModifiedFormatted}} </div>
<div class="expandedGrade" onclick="childDivClick(event)" style="display: none" id="grade-{{grade.gradeId}}">
<label>Attachments</label>{{grade.attachmentCount}}
<br />
<span ng-hide="editing" ng-click="editing = true"><b>{{grade.comment || 'No comments yet'}}</b></span>
<form ng-show="editing" ng-submit="editing = false">
<input type="text" ng-model="grade.comment" placeholder="Comment" ng-required />
<br />
<input id="saveChanges" type="submit" class="btn btn-primary" ng-click="saveChanges(this, grade)" text="Save changes" />
</form>
</div>
</li>
</ul>
As you can see we have a parent ul and for each grade in grades we simply display a li and a div that is hidden and when you click on the li we use jQuery to animate and display the hidden div. In the child div we have a comments field which users can update and click save. On save the current object gets fired back to the server however we are concerned about the fact that Angular has to go through all 2000 grades until it finds the one we are updating (due to two way binding) and this means that everything will be really slow and we cannot afford that.
This is what we want to achieve:
1 We want to bind the data one way so that we can display the list of all grades on the screen and as soon as they are all displayed we want to somehow remove the bindings.
2. When users update the comments for a particular grade we then want to dynamically bind that particular grade so that Angular knows exactly which one it has to update without having to go through the whole collection of 2000+ grades.
I have find a tutorial however I am still unsure how to integrate that into my code.
I have also watched this video and I understand the concept behind it but again, I am struggling to write something that actually works ( we have just started using Angular so I am pretty much a newbie)
Could anyone out there point me in the right direction and provide me with some code samples that would solve the issue we are facing? Any advice and help would be greatly appreciated
You could always use a directive
The logic should go like this
use a service to hold your grades
inject the service into your directive
make a copy and just bind the 'read only view' in your directive
you could watch the service for changes and makes updates as needed
in your directive
as far a lazy loading / updating when needed - use a data service
and call the data service for an update whenever the trigger fires
if your trigger needs to come as a push from some other 'web service' consider a technology
like http://socket.io/
I can put together an example if you would like to see how the services and directives should interact

AngularJS bind specific data to template

I'm currently making a switch from Knockout to Angular. The main problem I'm having right now is in transferring my original templates to something Angular will recognise.
Specifically, here's a bit of code I'm having trouble transferring:
<!-- ko template: { name: 'SquareTempl', data: Squares[5] } --><!-- /ko -->
In Knockout, this will attach Squares[5] to SquareTempl, so that when the template gets rendered, it does so using the members within Squares[5](or whatever data that gets attached).
I need to repeat the process for Squares[0]~Squares[11]. I can't use ng-repeat though since I won't be iterating through them in numerical order.
Ideally, it would be nice if I could do something along the lines of
<td class="Square" id="five" ng-include src="'SquareTempl.html'" ng-data="Squares[5]">
Any ideas?
Here's a JSFiddle I've written to outline a failed attempt I've tried using ng-model.
http://jsfiddle.net/fZz3W/9/
Two things: First, you can make ng-data be available by implementing it yourself YourApp.directive("ngData", function() {}) Secondly, do you need the HTML to be part of another file? An easy way to accomplish what you're looking for in Angular is with ng-repeat like:
<td ng-repeat="item in Square">
<div>{{item.name}}</div>
</td>
When the Square array is updated an additional post will be made.
Review your modified JSFiddle: http://jsfiddle.net/TdWMF/1/
So this is mostly a hack to achieve what you want, until I can offer you a better solution:
Second update using mixed order ng-repeat: http://jsfiddle.net/TdWMF/3/
Basically:
<div ng-repeat="index in [4, 2, 0, 3, 1]">
square index: {{index}}<br />
square: {{Squares[index]}}
</div>
Pretty ugly, and non-ideal, I know. I'd also recommend performing the order array generate in a function and then doing: ng-repeat="index in displayOrder(Squares)"

Categories