I have 3 tiles on a screen and on click of each of them, I am showing a pop up. Each tiles have their own pop up's inner content (not static content, also needs many functions) but pop up's header and footer sections are same. So, I have created a generic pop up with header and footer and sending the inner template according to individual tile's click. Onclick of a tile, I will get the tile's id and for inner template I have created the templates. So in generic ui pop up's controller, I am creating a variable for each pop up and checking that in generic popup and showing the correct inner template according to those variables. My problem is I don't want to create separate variable for each tile. Also in future, for each tile added, a variable needs to be added which is not good I feel. This solution is working without any error but I want to make it efficient somehow and need some help with the same. Please find the code below.
P.S: please forgive there are any typos in the code.
Folder structure:
- tilepopup
- ui
-genericpopup
- templates
- tileonetemplate
- tiletwotemplate
genericpopup.html
<div>
<tile-one-template show-content="genericpop.tile1"></tile-one-template>
<tile-two-template show-content="genericpop.tile1"></tile-two-template>
</div>
Template HTML for tileonetemplate.html
<div ng-show="showContent">
Some content
</div>
genericpopup.controller.js
class Genericpopup {
constructor() {
this.tile1 = false;
this.tile2 = false;
}
$onInit() {
this.setActiveTile();
}
setActiveTile() {
this.activeTile = this.stateObject.tileName; //on click of tile,
//I will get the tile name
switch(this.activeTile) {
case 'Tile 1':
this.tile1 = true;
break;
case 'Tile 2':
this.tile2 = true;
break;
}
}
}
Consider using the ng-include directive:
<div ng-include="'tilepopup/templates/'+ $ctrl.stateObject.name +'.html'">
</div>
For more information, see
AngularJS ng-include Directive API Reference
Related
First of all a disclaimer, I'm not a dev. I'm halfway through The Odin Project and have covered some HTML and CSS, but, have not yet started on JS. In order to help with my learning I've created my own blog. My aim is for each blog post to have its own stylesheet (so with each new post I learn a little more about CSS).
Anyway, I plan to write a post about the benefits of using an eReader, specifically the Kindle. I've styled the page to look like a Kindle Oasis, and I'd like the reader to be able to step through the article contents via the Kindle's next/prev buttons, but, as I'm not a dev, this is where I'm stuck. Via Stack overflow I've managed to add some JS that will display page 1, 2 and 3 via dedicated buttons for each dive element, but, what I really need is to step through x number of pages via the prev/next buttons.
Here's what I have so far: https://codepen.io/dbssticky/pen/yLVoORO. Any help would be much appreciated. What I should do of course is finish The Odin Project and come up with a solution on my own, but, I'd really like to get this Kindle article published sooner rather than later. Hence my rather cheeky request for assistance.
Here's the JS I'm currently using:
function swapContent(id) {
const main = document.getElementById("main_place");
const div = document.getElementById(id);
const clone = div.cloneNode(true);
while (main.firstChild) main.firstChild.remove();
main.appendChild(clone);
}
You have the right idea and it just needs a few adjustments to get the previous/next functionality.
Currently your div IDs are following the format operation1, operation2, and so on. Since you want the previous/next functionality you'll need to change your 'swapping' function, which currently takes the full ID, to use the numeric portion only.
Add a new function which appends the number to 'operation' instead of using the whole thing:
function goToPage(pageNumber){
const main = document.getElementById("main_place");
const div = document.getElementById("operation" + pageNumber);
const clone = div.cloneNode(true);
while (main.firstChild) main.firstChild.remove();
main.appendChild(clone);
}
And then change your Page 1/2/3 buttons to use goToPage(1), goToPage(2) and so on.
Now for the previous/next functionality you'll need a way to track which page you're on, so that you can figure out which page to load.
Add a variable at the top (outside functions)
var currentPage = 0;
Then add a line in your goToPage function to track the page you're on.
currentPage = pageNumber;
Now that you're tracking you can add a previous and next function.
function goNextPage(){
goToPage(currentPage-1);
}
function goPreviousPage(){
goToPage(currentPage+1);
}
Then call it from the previous and next buttons.
<button onClick="goNextPage()" class="next-button"></button>
<button onClick="goPreviousPage()" class="previous-button"></button>
Here's a codepen: https://codepen.io/srirachapen/pen/WNZOXQZ
It's barebones and you may have to handle things like non existent div IDs.
HTML
<button class="next-button" onclick="nextContent()"></button>
<button class="previous-button" onclick="prevContent()"></button>
JS
var pageid = 0;
var maxpage = 3;
function nextContent() {
if(pageid == maxpage) return
pageid++
swapContent(`operation${pageid}`)
}
function prevContent() {
if(pageid == 1) return
pageid--
swapContent(`operation${pageid}`)
}
you can try this to switch between pages. But you may need to edit the "swapContent" method more sensibly.
Track the Current Page
Whatever solution you use to render pages & links (manual hardcoded links & content vs externally-stored & auto-generated), one thing is unavoidable: You need to track the current page!
var currentPage = 0
Then, any time there's a page change event, you update that variable.
With the current page being tracked, you can now perform operations relative to it (e.g. +1 or -1)
I'd suggest making a goToPage(page) function that does high-level paging logic, and keep your swapContent() function specifically for the literal act of swapping div content. In the future, you may find you'd want to use swapContent() for non-page content, like showing a "Welcome" or "Help" screen.
Example:
function goToPage(page) {
// Update `currentPage`
currentPage = page
// ... other logic, like a tracking event or anything else you want you occur when pages change
// Do the actual content swap, which could be your existing swapContent()
swapContent('operation'+page)
}
You'd invoke the function like so:
goToPage(3) // Jump to a specific page
goToPage(currentPage + 1) // Go to the next page
goToPage(currentPage - 1) // Go to the prev page
You can make separate helper functions like "goToNextPage()" if you desire, but for sure you start with a fundamental page-change function first.
I'm using ng2-modal to create a modal dialog in Angular 2. I am unable to get an element that has a condition on it (#myModalScrollPanel).
Template (modal.html):
<modal #myModal title="{{title}}"
cancelButtonLabel="Close"
submitButtonLabel="Ok"
modalClass="#modal-md"
[hideCloseButton]="false"
[closeOnEscape]="false"
[closeOnOutsideClick]="false"
>
<modal-header></modal-header>
<modal-content>
<div class="row">
<div *ngIf="logOutput" class="col-md-12">
<div id="myModalScrollPanel" #myModalScrollPanel class="panel-body fixed-panel">
<p *ngFor="let entry of logOutput.entries">{{entry.log}}</p>
</div>
</div>
</div>
</modal-content>
<modal-footer></modal-footer>
</modal>
In my component I get View Children (modal.component.ts):
#ViewChild('myModal') myModalModal;
#ViewChild('myModalScrollPanel') myModalScrollPanel;
After a users clicks a button, I show the modal and get log text from the server, I call updateScrollPosition() once I have updated logOutput (modal.component.ts):
updateScrollPosition() {
console.log("modal:");
console.log(this.myModalModal);
console.log("log scroll panel:");
console.log(this.myModalScrollPanel);
if(this.myModalScrollPanel){
console.log("Scrolling the panel down");
this.myModalScrollPanel.nativeElement.scrollTop = this.myModalScrollPanel.nativeElement.scrollHeight;
} else {
console.log("No log scroll panel.");
}
}
The console shows a valid object for "modal" and 'undefined' for log scroll panel.
I also tried calling that method from ngAfterViewInit(), but it only gets called when the parent component is loaded, and not the actual modal being shown, so the if statement results in false and element doesn't exist yet. If I remove/move the if statement, so that the element exists I can then access that object, but the changes I make do not take any effect, although that might be a whole different issue (most likely to do with change detection).
In the end, I just want to scroll to the bottom of the panel. Something like this (which works in the browser console):
var scrollPanel = document.getElementById('myModalScrollPanel');
scrollPanel.scrollTop = scrollPanel.scrollHeight;
Thanks in advance!
So to answer my own question, I had to use #ViewChildren instead of #ViewChild.
#ViewChildren annotation will assign a QueryList object to your variable, giving you access to the elements you require (I use .toArray() to get an array of elements, which in this case will be just one).
Speaking of the change detection problem I had, thanks to this answer, using the ngAfterViewChecked() method I was able to implement the scroll down I needed.
Basically, I want to be able to show title and some text on hover on all my index thumbnail like this website.
http://www.timboelaars.nl/
However, in the current squarespace template that I am using (I believe it's called York), the markup is only grabbing the page title and therefore displaying the page title on hover. (See the below code block, you can see the page title in there, that's the only thing that the template displays on Hover)
<div class="index-item-text-wrapper">
<h2 class="index-item-title">
<a class="index-item-title-link" href="/google-shopping/" data-ajax-loader="ajax-loader-binded"><span class="index-item-title-text">**PAGE TITLE**</span></a>
</h2>
</div>
There's no field for me to put any HTML so I am seeking help to use javascript to manually inject custom HTML markup to every single thumbnail, then show them on hover.
TL;DR I want to be able to display more than just the title on hover (ideally my own HTML markup so I can customize the style) on my thumbnails but that's not supported by the template.
Here is my website http://shensamuel.com/
I am really weak at Javascript and I've searched for a solution for this problem for quite long. Any help will be much appreciated!
Thanks!
The following Javascript can be used to insert text for each tile on the page. The code would be inserted using the footer code injection area (unless you're using Developer Mode in which case you'd insert it with the rest of your scripts).
<script>
(function() {
var tiles = document.getElementsByClassName('index-section');
var thisTile;
var titleText;
var description;
var parent;
var i, I;
for (i=0, I=tiles.length; i<I; i++) {
thisTile = tiles[i];
titleText = thisTile.getElementsByClassName('index-item-title-text')[0];
parent = thisTile.getElementsByClassName('index-item-text-wrapper')[0];
description = document.createElement('span');
description.className = 'index-item-description-text';
switch(titleText.innerHTML.toLowerCase()) {
case "google shopping":
description.innerHTML = "Some custom text.";
break;
case "hana":
description.innerHTML = "More text that's custom.";
break;
case "wali":
description.innerHTML = "Custom text here.";
break;
case "cypress":
description.innerHTML = "Type anything you want.";
break;
case "ryde":
description.innerHTML = "Just another bit of text.";
break;
default:
description.innerHTML = "";
}
parent.appendChild(description);
}
})();
</script>
Observe the pattern in the code in order to add new tiles or edit existing ones. You will see that the script attempts to match (a lower case version of) the 'title' text and then inserts text based on each title. This allows you to add more in the future by repeating this 'case' pattern. Of course if you ever change the title of a tile you'd have to correspondingly change this Javascript code.
You can then style the description by inserting CSS via the Squarespace CSS Editor (or via your base.less file if using Developer Mode). For example:
.index-item-description-text {
display: block;
font-size: 1.2em;
color: #FFFFFF
}
Note that while there is an alternative method that would use each tile's respective URL to do an AJAX query and obtain meta data about each project (and therefore allow you to use the Squarespace content manager to insert this 'description'), that method seems unnecessarily complex for your case.
Update 8/17/2016: Regarding AJAX and how to disable AJAX loader in Squarespace: Jason Barone has suggested adding this snippet to your Code Injection > Footer to disable the "AJAX" pageloader. He noted that it will disable the smooth, AJAX transitions between pages, but will allow custom Javascript like usual.
<script>
//Credit: Jason Barone, http://jasonbarone.com/
window.Template.Constants.AJAXLOADER = false;
</script>
Also, some templates have an option to disable AJAX within the style editor (image credit: SSSUPERS):
Update 9/28/2016:
It has been reported that the code provided above no longer disable AJAX. However, some newer templates have added an 'Enable AJAX Loading' setting that can be toggled off.
I am using the tile example from polymers neon elements - and I am trying to make each expanded tile unique. My first try on how to do this was to pass a string in with the grid items like
{
value: 1,
color: 'blue',
template: 'slide-1'
}
And have that element be evaluated when rendered in a new element something like this. (this is the card template itself)
<template>
<div id="fixed" class$="[[_computeFixedBackgroundClass(color)]]"></div>
<div id="card" class$="[[_computeCardClass(color)]]">
<[[item.template]]></[[item.template]]>
</div>
This does not work - however I am wondering if there is some way to do this so I can load custom elements for the content of each card. For reference -https://elements.polymer-project.org/elements/neon-animation?view=demo:demo/index.html&active=neon-animated-pages , it is the grid example and I am trying to replace the content of each card once it is clicked on ( the fullsize-page-with-card.html, here is all the html for it - https://github.com/PolymerElements/neon-animation/tree/master/demo/grid ). Is this the wrong way of approaching this? Or maybe I have some syntax wrong here. Thanks!
Edit : OK, So I can send it through if i add it to the click to open the card like so
scope._onTileClick = function(event) {
this.$['fullsize-card'].color = event.detail.data.color;
this.$['fullsize-card'].template = event.detail.data.template;
this.$.pages.selected = 1;
};
and in the card's properties like so
template: {
type: String
},
So I can then evaluate it as [[template]] , however - the question still remains how to call a custom element (dynamically) using this string. I could pass a couple of properties and fill in a card or form so they are unique, but i think I would have much more creative freedom if I could call custom elements inside each card.
I have an element that allows referenced templates. There are a couple of others other there, but this one also allows data bindings to work: https://github.com/Trakkasure/dom-bindref
I'm trying to make a page with two sections, which can be slid back and forth horizontally to take up different relative widths on the page. The idea was to track the percentile width of the (to-be) draggable bar separating the two panes/sections, and use ng_style to automatically update the widths of the two "panes" in relation to where that bar is dragged.
The following is in a Rails app, with integrated Angular. The Angular's loading just fine -- no errors, and the rest is all working -- and the ng_style is being loaded from the Angular controller when the page first loads up -- but it's not changing when I attempt to drag the spacer in between the two "panes", as it's supposed to.
Here's a simplified version of my HAML (sorta like Jade. Just indented HTML):
#full-page.fluid{ ng_controller: "ExerciseCtrl", ng_mousemove: 'updateSidebarWidth($event)', ng_mouseup: 'untrackMouseMove()', ng_cloak: true }
.spacer
.fixed-section-container
.exercise-show
%div
.sidebar-section{ ng_style: '{{ sidebarWidthStyle }}' }
.sidebar_header
.sidebar
%div{ markdown: #exercise.body }
.sidebar-toggle{ ng_mousedown: 'trackMouseMove()' }
.work_area{ ng_style: '{{ workAreaWidthStyle }}' }
And here are the relevant lines in my (Coffeescript) Angular Controller.
$scope.sidebarWidth = 35
$scope.trackingMouse = false
$scope.trackMouseMove = -> $scope.trackingMouse = true
$scope.untrackMouseMove = -> $scope.trackingMouse = false
$scope.updateSidebarWidth = (event) ->
if $scope.trackingMouse
pageWidth = $('.emelyn-layout.middle.fluid').width()
x_percent = (event.pageX * 100) / pageWidth
x_percent = Math.max( Math.min(100, x_percent), 0 )
$scope.sidebarWidth = x_percent
$scope.workAreaWidthStyle = { width: "#{99 - $scope.sidebarWidth}%", marginLeft: "#{$scope.sidebarWidth + 1}%" }
$scope.sideBarWidthStyle = { width: "#{$scope.sidebarWidth}%" }
In other words, I have this .sidebar-section on the left, then a .sidebar-toggle (just a vertical bar), which should be draggable (which causes the width styles to change, once I get this working), and then the .work-area, which is resized, along with the .sidebar, on drag of the toggle.
The issue is that, although the ng_styles are loaded on page load, and although the ng_style values visibly change when I inspect the page and drag the toggle bar, the ng_style changes aren't propagating to the style attributes of the given elements.
In other words, when I inspect the element, I see something like this:
<div class="work_area" ng_style="{ 'width':'48.142857142857146', 'marginLeft':'51.857142857142854' }">
I took a look at this post and tried wrapping updates to the styles in a $scope.$watch, but that didn't change any of the above behavior at all, and it seems wrong to me -- the docs on ng_style suggest to me that the way I'm using it should be effectively correct -- as in, Angular handles the binding for you, without your needing to explicitly tell it when to update the DOM jQuery style.
Any ideas what I'm doing wrong and how to fix it? (Or what might be a better or easier way of doing the above?)
Thanks, and please let me know if you'd like to see any other files or anything,
Sasha
ngStyle works a little differently than what you have. It is evaluated as is, no need for {{}} to point to a $scoped variable.
#full-page.fluid{ ng_controller: "ExerciseCtrl", ng_mousemove: 'updateSidebarWidth($event)', ng_mouseup: 'untrackMouseMove()', ng_cloak: true }
.spacer
.fixed-section-container
.exercise-show
%div
.sidebar-section{ ng_style: 'sidebarWidthStyle' }
.sidebar_header
.sidebar
%div{ markdown: #exercise.body }
.sidebar-toggle{ ng_mousedown: 'trackMouseMove()' }
.work_area{ ng_style: 'workAreaWidthStyle' }
When you use {{}} it evaluates that to a string and then runs it through ngStyle. ngStyle ends up watching a string and not a variable.