I have a DIV inside my HTML page like this in my angular application,
<div id="graph" *ngIf="newRequired == 0"></div>
I want to load a graph inside the container, my Container code is like this
Element createContainer() {
var e = new DivElement()
..style.height = '300px'
..style.maxWidth = '70%'
..style.marginBottom = '50px';
document.body.append(e);
return e;
}
This working fine... the problem I am facing since the element is dynamic one.. so the graph loads at the bottom of the page.
Instead I want to load the graph inside the DIV id="graph" (already inside the HTML page).
I feel to do this we have to change the code here document.body.append(e)... can anyone help me how to bring the graph since the DIV id="graph"
If you're trying to add code inside your div, replace document.body.append(e) with document.getElementById('graph').innerHTML = e.
Alternatively since it looks like you're using jQuery you can try $('#graph').append(e).
DOM manipulation - especially injection is completely incoherent with what Angular is trying to achieve with its framework. In the last couple years I've spent working with Angular, I've not had a single occasion where I have needed to do something like: document.body.append(e);.
What you should be doing instead is using property binding in html.
So...
Element createContainer() {
var e = new DivElement()
..style.height = '300px'
..style.maxWidth = '70%'
..style.marginBottom = '50px';
document.body.append(e);
return e;
}
Will transform into:
In component:
export class ExampleComponent implements OnInit {
public height: number;
public maxWidth: number;
public marginBottom: number;
...
}
In html:
<div id="graph" *ngIf="newRequired == 0">
<div [ngStyle]="{'height': height, 'max-width': maxWidth, 'margin-bottom': marginBottom}"></div>
</div>
With this approach if you need to change your height for whatever reason, all you have to do is change the properties in the component and the html will update. If you go with your original approach of document.body.append(e) you would have to manually update these values.
Related
I read many articles and documentations about this but none of them seem to take the approach I'm trying to make.
I have an array of category Items and inside it I have a nested array of said category products.
like so.
<ng-container *ngFor="let menu of menuList">
<ng-container *ngFor="let item of menu.catItem" >
<div class="card" #cmp >
just to demonstrate
<button class="animateIt(cmp)"> click to animate </button>
</div>
</ng-container>
</ng-container>
when the user click the button I would like to add some kind of animation to, I can do that without any problem but the issue is I cannot think of a way to this without using any extra JavaScript libraries.
I have tried adding ViewChildren to my component. And a function that print the element
#ViewChildren('cmp') components: QueryList<ElementRef>;
constructor(private renderer: Renderer2){}
animateIt(cmp:ElementRef){
console.log(cmp);
this.renderer.setAttribute(cmp.nativeElement, 'class', 'myClass');
}
second line inside the function gives an error since cmp.nativeElement is not defined which is expected since all it does is to grab the content of the div and just print it without making an ElementRef object.
Is there any way I can achieve this using just angular or just JS?
I think you need to retrieve your element in ngAfterViewInit lifecycle, like below:
ngAfterViewInit() {
this.cmp.changes.subscribe(() => {
console.log('changed');
})
}
did it by using plain JS
here is the code
animateIt(cmp:ElementRef){
this.el.nativeElement = cmp;
let element = document.createElement('div');
element = this.el.nativeElement.cloneNode(true);
element.style.position = "absolute";
element.style.top = this.el.nativeElement.offsetTop + 'px';
element.style.left = this.el.nativeElement.offsetLeft + 'px';
let parent = document.getElementById("parent");
parent.appendChild(element);
}
this is my script coding for left side menu slide left and right. I want to convert it into angularJS, I copied it from other website and unable to understand.
<script>
var menuLeft = document.getElementById('cbp-spmenu-s1'),
showLeftPush = document.getElementById('showLeftPush'),
body = document.body;
showLeftPush.onclick = function() {
classie.toggle(this, 'active');
classie.toggle(body, 'cbp-spmenu-push-toright');
classie.toggle(menuLeft, 'cbp-spmenu-open');
disableOther('showLeftPush');
};
function disableOther(button) {
if (button !== 'showLeftPush') {
classie.toggle(showLeftPush, 'disabled');
}
}
</script>
I can see that this code is some sort of toggle functionality. So let me try to explain how we can convert this!
The code starts at the onclick, so in angular that will be ng-click, also in angular you can write this in the HTML like so
<button id="showLeftPush" ng-click="test=!test;" ng-init="test=false;" ng-class="{'active': test, 'disabled': test}"></button>
In the above line, I will initialize test variable to false. then ng-click will toggle this variable. Then you are toggling the active class for the button. So the angular equivalent for that will be ng-class where the test will be a boolean, if test is true, then the class will be added. I do the same thing for disabled class also.
Similarly I add the other classes to the other element like.
Body HTML:
<body ng-class="{'cbp-spmenu-push-toright': test}" ng-controller='MyController' ng-app="myApp">
Div with ID - cbp-spmenu-s1:
<div id="cbp-spmenu-s1" ng-class="{'cbp-spmenu-open': test}">left</div>
Please use this as a starting point and continue building you angular App.
I have included a demo for your reference.
JSFiddle Demo
Hi I would like to know if the is a way to tell ember to initialize immediately after the root Element?
For example I have this DOM Structure:
<div id="#bodyContent" class="ember-application">
<div data-name="ContentPlaceHolderMain">
</div>
<div id="ember357" class="ember-view">
</div>
</div>
But I Want ember to be first on the DOM:
<div id="#bodyContent" class="ember-application">
<div id="ember357" class="ember-view">
</div>
<div data-name="ContentPlaceHolderMain">
</div>
</div>
In my enviroment.js file I have this line:
ENV.APP.rootElement = "#bodyContent";
Is there any way to achieve this?
Ember uses appendTo to insert it's view inside root element. But you could override didCreateRootView of ember instance and change it to use prependTo. Have a look how Fastboot does this.
Update: This is an instance-initializer to overwrite didCreateRootView.
export function initialize(appInstance) {
appInstance.didCreateRootView = function(view) {
// overwrite didCreateRootView
};
}
export default {
name: 'prepend-to',
initialize
};
ember/glimmer does not provide an prependTo method. You have to implement that one on your own following the implementation of appendTo.
Please also note that didCreateRootView is a private hook. Don't expect that one to keep stable over time.
In general I would not recommend to go this path if there is any other way to achieve your goal. Please consider adding a container for ember at desired position. If you don't have control over HTML markup you might could add a container using jQuery before initializing ember.
Update 2:
import jQuery from 'jquery';
export function initialize(appInstance) {
appInstance.didCreateRootView = function(view) {
let containerId = 'ember-container';
jQuery('<div>').prop('id', containerId).prependTo(jQuery(this.rootElement));
view.appendTo(`#${containerId}`);
};
}
export default {
name: 'prepend-to',
initialize
};
This is not exactly what you've asked for but it's much easier to achieve. If your HTML markup looks like <body><div id="existing-content"></body> and body as default root element above instance initializer will add another div #ember-container before #existing-content and using this one as embers root element.
Update 3:
You find an ember-twiddle here: https://ember-twiddle.com/43cfd1ae978b810f2e7cf445f9a3d40c?openFiles=instance-initializers.root-element.js%2C
If you inspect DOM you will see that ember root element is wrapped by <div id="ember-container"></div>. This wrapper is append to rootElement. So it's before any existing content in rootElement. I guess it's not possible to define a custom index.html in ember-twiddle so I can't demonstrate this one. But you could easily test yourself.
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.