I have a product page, and there is an option for a 'quick view' which opens the product description and images in a modal. I also have a 'full details' button where I would like the user to be taken to a new URL based on the item code, but also display the information from my JSON for that clicked product. This is what I have:
<a ng-click="store.selected = product" ng-href="{{store.selected.code}}.html" class="btn btn-sm">Full details</a>
Everything works great for the Modal, so I am presuming there is a problem moving onto a different page and carrying this information across? I have mocked it up in Plunker to show the problem:
Plunker here
Any help would be much appreciated.
You should consider using ng-route to switch the view to a different html file. But you can also use ng-include with a little less set up.
When the Full details link is clicked, toggle a variable that tracks whether the gallery or the details should be visible. And, construct the path to the html template you want to display:
$scope.setSelection = function(product) {
$scope.store.selected = product;
$scope.detail.show = !$scope.detail.show;
$scope.detail.source = product.code + '.html'
}
Then, use ng-include to display the template:
<div ng-if="detail.show" ng-include="detail.source">
</div>
Here is an update of your plunker: http://plnkr.co/edit/zhsY6TAjONewyInGiwUC?p=preview
Note that the template should just be a snippet of html.. you don't need to include scripts like angular again.
Related
I'm trying to create a custom element for reuse. What I have is data consisting of three attributes that will be displayed on it's respective page, depending on the link you click.
I'm using the Polymer Starter Kit. Basically, I want to have a page of information that changes depending on what the URL is. I have a list of programs on a page with links to their respective pages. So far I have this:
In my index.html, I have a section that looks like this:
<section data-route="programs">
<paper-material elevation="1">
<h1>Programs</h1>
<a href$="{{baseUrl}}programs/firstprogram">Program 1</a></br>
<a href$="{{baseUrl}}programs/secondprogram">Program 2</a></br>
<a href$="{{baseUrl}}programs/thirdprogram">Program 3</a></br>
</paper-material>
</section>
Then I have a custom element, program-info, that looks like this
<dom-module id="program-info">
<template>
<h2 class="page-title">{{program.name}}</h2>
<p>{{program.price}}</p>
<p>{{program.description}}</p>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'program-info'
});
})();
</script>
</dom-module>
Based on the program that was clicked, I want to grab data and use it in my custom element (name, price, description). I've thought about putting it in an array since there are only seven programs, but I don't know understand how to grab the right item in the array based on the URL.
Any thoughts?
If you are indeed using PSK, take a look at the section/page user-info in app/index.html. It displays information about a user based the name that was grabbed from the URL.
Of course you should also take a look at the routing configuration in app/elements/routing.html to figure out how the name is grabbed from the URL and set to the params variable.
Then you should add/modify your programs route to suit your needs.
Edit:
You can see a similar approach in this sample app : The data is fetch when the route changes and is then set to an article property in the scope of the blog-app element. In this element, said article property is itself bound to the similarly named property of the "page element" article-detail that is in charge of displaying the article's content that was previously fetched over the network.
I have created a uib-accordion in my Angular website and can get most of the functionality I want, with dynamic content changing accordingly.
I am having trouble styling the uib-accordion-group dynamically.
<uib-accordion-group panel-class="panel-danger">
<uib-accordion-heading>
Accordion Heading 1
Is fine and colours the whole heading Red/Pink, I want to change this to panel-warning or panel-info based on other variables on the page.
<uib-accordion-group panel-class="{{getPanelColor()}}">
<uib-accordion-heading>
Accordion Heading 1
The function seems to be called correctly and is triggered correctly with ng-click elsewhere.
I appears that I cannot change the value panel-class uses dynamically. So in this instance getPanelColor() returns 'panel-danger', 'panel-info' or 'panel-warning' depending on other variables. If I print this return value out on the page in another div or whatever it changes correctly. If I refresh the page the correct colours are displayed for the changed panel-group.
Is there another way of setting the color - I don't know what the classes are for the accordion-group. I have tried changing the color of a div withing the panel, but this is a child element and does not change the color of the whole heading.
Any help much appreciated. (I'll come up with a JSFiddle if the question is not clear)
If you look at the HTML after the panel-class has changed and Angular has digested the change, you will see this line:
<div class="panel panel-danger" ... panel-class="panel-default">
That is, there is a mismatch between class and panel-class (the former has panel-danger, whereas the latter has panel-default). The uib-accordion-group directive simply does not handle the change in the wanted manner.
One workaround is to add ng-if to the whole group:
<uib-accordion-group ng-if="render" panel-class="{{getPanelColor()}}">
... and just before you want to change panel-class, remove the whole element temporarily, so that Angular re-renders it from scratch. Hopefully, the following code explains the principle:
$scope.render = true;
$scope.panelColor = 'panel-danger';
$scope.setPanelColor = function(val) {
$scope.panelColor = val;
$scope.render = false;
$timeout(function () {
$scope.render = true;
});
};
$scope.getPanelColor = function() {
return $scope.panelColor;
};
See the proposal in action: http://plnkr.co/edit/XfJiPnNi1z4F9cgIVxxw?p=preview. Press 'Clear panel color OK'.
The downside is that the removal of the element causes some flickering.
I have added another button 'Clear panel color FAIL' that shows what happens in your failing case. Here is what the HTML looks like after you press the button, notice the mismatch panel-danger vs. panel-default:
Use an interpolated expression in the class attribute, for example:
class="{{!ctrl.valid?'notValid':'valid'}}"
I am using Angular UI Bootstrap http://angular-ui.github.io/bootstrap/. I have two questions:
I followed the example given at angular-ui.github.io, there they use
<script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js">
but I don't want to use the CDN so I downloaded Angular UI and added it to my project. How to include it into my code?
I did add
['ui.bootstrap'] to my angular.module, but it's not working until I add the above script code.
I'm using <tabset> to create two tabs, contacts and group. For
example, a user is in the Group tab, he wants to add members to an existing group, so if he clicks the Add Member button, I want to navigate to the Contacts tab automatically.
I thought of using document.getElementByTagName() inside my
controller. Will it work? And what is the Angular way to click
something programmatically.
Question #1:
<script src="folder_of_js/ui-bootstrap-tpls-0.10.0.js"></script>
Question #2:
You don't use document.getElementByTagName() with AngularJS, if you want to navigate to a tab while you are in another tab's content, an example might be the following:
<tabset>
<tab ng-repeat="tab in tabs" heading="{{tab.title}}">
{{tab.content}}
<button class="btn btn-default btn-sm" ng-click="tabs[2].active = true">Select third tab</button>
</tab>
</tabset>
As you can also see in this plunker, I added a button that navigates to the third tab whenever you click it.
The script file is probably not loaded by the browser. You have to add a script tag pointing to where the file is in your project. For example, if the script is placed in the folder /scripts/lib/:
<script src="/scripts/lib/ui-bootstrap-tpls-0.10.0.js" />
One of the golder rules of AngularJS is to never, for any reason, referrence the DOM (i.e. an HTML element) from a controller. So while document.getElementByTagName() will technically work, I would advice against it.
In angular, you really don't click things programmatically. The common way is to bind something in your HTML to a variable in the $scope, either by curly brackets ({{someVariable}}), or by directives such as ng-class, ng-bind etc. Then you change that variable in $scope, and the HTML changes to reflect that. Is there a variable in $scope which determines which tab is open? If so, you can just change that variable, and it should work automagically.
I'm trying to create a simple time picker directive. http://plnkr.co/edit/VYGqhPbHf1yqXLpemGEP
When user click on input field I want to display the content of my template html as a dropdown below the input (will take care of css later) so that user can select a time from the list. I'm not sure how to get hold of the template (something like angular.element(template).show())
Thanks!
Edit: I managed to come up with this: http://plnkr.co/edit/zAplNKVfohXLbIzwjhy4?p=preview
Everything works except when I click any of the list, it does not set the correct model value.
Try the following:
Embed the the HTML for the date picker list
Hide the list from the html
If the input gets focus change the visibility.
Pseudo code:
HTML:
<ul ng-show="listVisible">
<li> .... </li>
</ul>
JavaScript
scope.listVisible = false;
element.$on('focus', function() {
scope.listVisible = true;
});
Do something similar in reverse.
I managed to get it working. I had to create a new scope for the dropdown element. http://plnkr.co/edit/zAplNKVfohXLbIzwjhy4?p=preview
I am using the accordion directive from http://angular-ui.github.com/bootstrap/ and I need to have more control over when the accordions open and close.
To be more precise I need a button inside the accordion-group that will close its parent accordion and open the next one (so basically mimic what clicking the next header would do if close-others was set to true).
I also need to do some validation before I can allow an accordion to be closed and the next one to be opened, and I also need to wire this up to click events on the accordion headers.
I am pretty new to angular and we're currently rewriting an application from Backbone+JQuery to Angular. In the Backbone-version we were using Twitter Bootstrap accordions and we were opening and closing them using JQuery. While we can still keep doing this I would rather get rid of JQuery DOM manipulation completely so I am looking for a pure angular solution to this.
What I've tried to do in terms of validation is
<accordion-group ng-click="close($event)">
and in my controller
event.preventDefault();
event.stopPropagation();
This obviously did not work as the DOM element is replaced by the directive and the click-handler is never added. I've been going over the source code (and found a few very nice undocumented features) but I'm at a loss over where to even begin solving this specific challenge. I was considering forking angular-ui and try to add this functionality to the accordion directive but if I can achieve this without modifying the directive that would be a lot nicer.
There is the is-open attribute on the accordion-group which points to a bindable expression. By using this expression you can control accordion items programatically, ex.:
<div ng-controller="AccordionDemoCtrl">
<accordion>
<accordion-group ng-repeat="group in groups" heading="{{group.title}}" is-open="group.open">
{{group.content}}
</accordion-group>
</accordion>
<button class="btn" ng-click="groups[0].open = !groups[0].open">Toggle first open</button>
<button class="btn" ng-click="groups[1].open = !groups[1].open">Toggle second open</button>
</div>
and the working plunk here: http://plnkr.co/edit/DepnVH?p=preview
For whoever the solution by #pkozlowski.opensource is not working (me for example) you could just force the component to accept the CSS that will close it (without transition that is).
The Theory: The angular directive gets expanded into standard HTML, div elements mainly, where the CSS styles give it the appearance of the accordion. The div with class .panel-collapse is the body of the accordion-group element. You can swap its second class from .in to .collapse along with a few other changes as seen below.
The Code:
$scope.toggleOpen = function(project) {
var id = '<The ID of the accordion-group you want to close>';
var elements = angular.element($document[0].querySelector('#'+id));
var children = elements.children();
for(var i = 0; i < children.length; i++) {
var child = angular.element(children[i]);
if(child.hasClass('panel-collapse')) {
if(child.hasClass('in')) { // it is open
child.removeClass('in');
child.addClass('collapse');
child.css('height', '0px');
} else { // it is closed
child.addClass('in');
child.removeClass('collapse');
child.css('height', 'auto');
}
}
}
};
As we are talking about Angular, it is very possible that you are generating the accordion through an ng-repeat tag. In this case you can also generate the id's for the elements like:
<accordion-group ng-repeat="user in users"
is-disabled="user.projects.length == 0"
id="USER{{user._id}}">
Given a Mongoose model User, notice that the id I am giving is not user._id but has 'USER' appended in front. This is because Mongoose might generate id's that start numerically and querySelector does not like that ;-) go figure!