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.
Related
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
Having a hard time grasping AngularJs.. How would you build something like this simple textfields and animations in AngularJS? I had been looking into using directives but it just isn't adding up to me much. I had been trying to base this from what I learned online but was not having much luck
http://codepen.io/yusufbkr/pen/RPBQqg
HTML:
<div class="materialContainer">
<div class="title">LOGIN</div>
<div class="input">
<label for="name">Username</label>
<input type="text" name="name" id="name">
<span class="spin"></span>
</div>
<div class="input">
<label for="pass">Password</label>
<input type="password" name="pass" id="pass">
<span class="spin"></span>
</div>
<div class="button login">
<button><span>GO</span> <i class="fa fa-check"></i></button>
</div>
Forgot your password?
<div class="title">REGISTER</div>
<div class="input">
<label for="regname">Username</label>
<input type="text" name="regname" id="regname">
<span class="spin"></span>
</div>
<div class="input">
<label for="regpass">Password</label>
<input type="password" name="regpass" id="regpass">
<span class="spin"></span>
</div>
<div class="input">
<label for="reregpass">Repeat Password</label>
<input type="password" name="reregpass" id="reregpass">
<span class="spin"></span>
</div>
<div class="button">
<button><span>NEXT</span></button>
</div>
just use the codepen link ( http://codepen.io/yusufbkr/pen/RPBQqg ), stackoverflow won't let me input the rest of the code...
Thanks! Any help would be incredible
I'm just learning Angular myself. From what I know, you're on the right track to be thinking of directives for swapping out interactive parts of the DOM. I suspect you'll also be needing ui-router for dealing with the widget outcomes (I hear it's the industry standard, vs the built-in ngRouter).
I'm partly writing this out to make sure I understand it, so I hope other, more knowledgeable people will come by and answer any questions you have about it (or point out where I'm misundertanding something.)
So you bring the webpage into the Angular world by, for instance, making the <html></html> tags into <html ng-app="yourApp"></html>. The unchanging html that will be the same on every view is in the index.html file. Put the html for the boxes is in another html file, say box.html. On the index.html file in the place where you want to have your boxes appear, put <div ui-view></div>. The ui-view connects to ui-router. Down at the bottom of the index.html right before closing the body tag, put
<script src="lib/angular/angular.js"></script>
<script src="lib/angular-ui-router/release/angular-ui-router.js"></script>
<script src="app/app.js"></script>.
In app.js, you put something like,
angular.module('yourApp', [
'yourApp.box',
'ui.router'
])
.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
$urlRouterProvider
.otherwise('/signin/child');
$stateProvider
.state('box', {
url: '/signin',
templateUrl: 'app/box/box.html',
controller: 'BoxController'
})
.state('box.child', {
url: '/child',
template: '<span>{{ definedProperty }}</span>'
});
})
});
Starting at the top, you name angular, call its module function, and give it the parameters ('theNameYouChose', ['dependencies','required'])
In the config bit there, you're telling it about dependencies config needs. $stateProvider and $urlRouterProvider are ui-router things, and $httpProvider is, I believe, an angular thing that is still necessary.
In the urlRouterProvider, you're providing the default address the website goes to: in this case it happens to be a template within a template, /signin from the signin state, and /child from the specifics pasted into signin
In the states, you are giving names and properties to the URLs that will be part of your app: like, if someone goes to index.html/signin, the 'signin' state is summoned.
The template within a template might be how you'd get the box variability that you're looking for. In box.html you will have another <div ui-view></div> and that's where the varying thing described in 'signin.child' gets put in.
box.html is also the place you put your specially created html tags, the ones you will make with the directive. I'll talk through those below.
The parent template, 'signin', talks about BoxController. Let's say you built that in box.js. It would look like this:
angular.module('yourApp.box', [])
.controller('BoxController', function ($scope) {
$scope.definedProperty = 'reRegPass',
$scope.arrayOfObjects = [{prop: 'red'},{prop: 'blue'}]
})
.directive('specificBox', function(){
return {
restrict: 'EA',
templateUrl: 'app/box/box-guts.html',
replace: true,
scope: {
source: '='
},
link: function(scope, element, attribute) {
element.on('click', function() {
alert('Functionality in specificBox is working');
}
}
}
});
The first line is again summoning angular module, and then naming it: note we already listed this, 'yourApp.box', as a requirement in app.js. Then we have the controller-naming function, and the appearance of specific properties in their $scope.
The directive is taking the more useful of the two forms a directive can take. They can either return functions (with signatures like the one in .link), or they can return objects that describe new HTML entities. This one is named specificBox, which Angular will translate into <specific-box></specific-box>. This object (technically called a 'directive definition object') can be translated into HTML tags because of the restrict property... 'E' is for element. 'A' is for attribute. I don't know how something that can be an element could also be an attribute, but having both options works, so I'm going with it. (Maybe for your various signin boxes you want a directive that has just 'A' to make new types of attributes.)
You put these specifically-crafted tags into box.html, and everything in box-guts.html will be between those tags... In fact, replacing those tags because of the replace: true.
The .link property is where you would put a function that would do something interesting to that element; turn it red if clicked, whatever. I have an alert example. Uses jQuery Lite for events.
The .scope property is odd. I believe if left off, the specific-box stuff would have the same controller as box (ie, BoxController), with box's scope and dependencies. But here, instead, we're making an isolate scope. box-guts will not depend on anything or have access to anything built before. How will it get interesting changeable data, then..? Every property in the scope object becomes an attribute on specific-box.
The '=' means that you will pass it objects from somewhere, and they will have 2-way data binding (changes made in box-guts will be reflected in the object collection in your app). Other options are '#', one-way data binding, which means you're passing box-guts a string or something that, if it changes in the DOM, you don't care to reflect in your app; or '&' to give it a function from a controller somewhere else in your app.
So ultimately, in box.html, you will have something like
<div class="box-holder">
<div ui-view></div>
<specific-box source="thing" ng-repeat="thing in arrayOfObjects"></specific-box>
</div>
Like I said above, ask questions and maybe we can sort this out.
I have two controllers allocated to two views:
[ResultsView ng-controller="ResultsCtrl"]
[SearchView ng-controller="SearchCtrl"]
The Search View has many complex filters/options and is filled in by the user, then he/she can press "Search" on SearchView and Results should be populated into a Grid.
Now I can send information between two either by a Service or by using $rootScope.$broadcast.
Heres the problem I've run into:
[ResultsView ng-controller="ResultsCtrl"][SearchView ng-controller="SearchCtrl"]
[ResultsView ng-controller="ResultsCtrl"][SearchView ng-controller="SearchCtrl"]
[ResultsView ng-controller="ResultsCtrl"][SearchView ng-controller="SearchCtrl"]
If I were to have multiple Result-Search sections on the same page, how can I ensure they each act independently from each other? Using the Service approach, the ResultsCtrl and SearchCtrl both have the defined service
.controller("searchCtrl", ["$scope", "$searchHttp", function ($scope, $searchHttp) {
.controller("resultsCtrl", ["$scope", "$searchHttp", function ($scope, $searchHttp) {
So I can't change how each instance of the controller behaves regarding the service. Soon as one SearchCtrl calls the service, it will modify every ResultsCtrl instance.
Likewise using broadcasts $rootScope.$broadcast("searchResults"... will be picked up by every ResultsCtrl instance.
So whats the best way around this? I want to reuse the Results and Search View code since its basically the same. But I need to render each pair independently on the same page a few times.
I think the HTML structure you need is something like this.
<!--First-->
<div ng-controller="SearchCtrl">
<div ng-controller="ResultsCtrl">
</div>
</div>
<!--Second-->
<div ng-controller="SearchCtrl">
<div ng-controller="ResultsCtrl">
</div>
</div>
This HTML structure would help you to use independently the search results one's parent SearchCtrl created in ResultsCtrl.
jsfiddle is here.
I hope this would help you. :)
I'm building SPA application with knockout.js .
Basically what i do is bind as current page a ko component depending on what is route.
It looks something like
<div id="currentPage" data-bind="component: { name: currentRoute.page,
attr: currentRoute }>
</div>
This is for the current page and the whole picture whit the layout looks like:
<html>
<head></head>
<body>
<div data-bind="component: {name: "nav"}></div>
<div data-bind="component: {name: "aside"}></div>
<div id="currentPage" data-bind="component: { name: currentRoute.page,
attr: currentRoute}">
</div>
</body
</html>
The problem is that i dont have one layout.. the other one looks like this (pseudo used)
<html>
<body>
<wrapper>
<currentPage>
</wrapper>
</body
</html>
So basically the first layout is not direct parent of the currentPage module but the second is..
The variants for dynamic layout changing that i can think of are
Specify the layout components in each page.. But i dont think it is good idea cause i will be writing the same code over and over and will not be able to persist the state in the layout component because of when i change the next page the layout will be recreated( not fully but enough to loose the state )
The layout is separate from the currentPage component so only the currentComponent binding will be changed.. this is perfect for persisting state in layout but not good when i have variant where i want different layout for example which is wrapper around the componentBinding..
I'll be very happy if some one shares fresh ideas how to solve such problems.
In knockout if any part of view is to be dynamically changed you got to have bindings attached to the view. You say that the outer layout of the page is dependent on the inner page being displayed, so logically I consider it part of that page view definition. That is why I would not look for some special way to handle this case.
If I am not missing something, the reasonable thing to do in this case is to just include layout in each page. You could then handle repetitive code by using "traditional" approach using knockout templates (especially Note 5 on dynamic templates from http://knockoutjs.com/documentation/template-binding.html) and code extraction.
Completely other approach you might want to take is to put all layouts in master page and then control them by using bindings like "if" and "visible".
I try to make tabs with Angular bootstrap.ui Tabs. Static tabs work, but dynamic don't show title and content. Below my code:
My JS:
(function (angular) {
angular.module('numeter', ['ui.bootstrap']).
controller('configurationMainTabCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.maintabs = [
{ title:"Users", content:"Test", url:"/user" },
{ title:"View", content:"", url:"/view" },
];
}]);
}(angular));
My HTML:
...
<div ng-controller="configurationMainTabCtrl">
<tabset maintabs>
<tab ng-repeat="maintab in maintabs">
<tab-heading>{{maintab.title}}</tab-heading>
{{maintab.content}}
</tab>
</tabset>
</div>
...
This code show me empty tabs selectable with empty content.
Since you didn't include all your code, I'm not sure if this was the problem, but in future it'd be mighty helpful if you linked to a plunker or fiddle. That way, we can see the code in action, and it's also easier to fork that with the solution. (Plus I find plunkers handy for narrowing down things to just the exact code I'm working on, which helps me troubleshoot.)
Here's a plunker with your code, edited: http://plnkr.co/edit/u80OhmN7YqYRytFE7kG5?p=preview
When using your setup, the only error I got was that it couldn't see your controller as a function, which means it's not picking up on the ng-app. As soon as I add ng-app="app" to the body tag, everything started working. Since I've only got the code you posted, I'm not sure, but that might've been one problem.
The other possible culprit might be these two lines:
<tabset maintabs>
<tab ng-repeat="maintab in maintabs">
change them to this:
<tabset>
<div ng-repeat="maintab in maintabs">
and then things should be behave. Otherwise you've got ng-repeat on the tab directive, when the directive expects just one tab per, well, tab. Put the part inside the ng-repeat, not alongside it, I mean.
Not sure if its relevant to your case, but I had the same issue in a different scenario. If you are using ng-include like this <div ng-include="'mytemplate'" ng-controller="MyCtrl"></div>, then there is a scoping problem somewhere between 1.1.6 and 1.2.2 which might explains why you might not be seeing maintabs.
Thanks for all your responses.
It was a noob mistake. I use Django and {{...}} are evaluated by Django template system. I add {% verbatim %} tag to escape angular part and it works.