I am trying to use angular directives to dynamically replace an html portion of a portlet of a page.
The html portlet has 2 sections embedded. The top part has the heading which is obtained from a different backend service
<div class="headerdiv">
<h3 class='headerclass'> Object Heading </h3>
</div>
The content is loaded in to a different section
<div id="objectDiv" ng-controller="ObjectCtrl">
<div ng-show="object.title" mydirective><b>{{object.title}} </b></div>
<div element-trigger><b>{{object.name}} </b></div>
<div element-trigger><b>{{object.description}} </b></div>
</div>
The controller loads the details successfully
The new directive added is
app.directive('mydirective', function(){
return function(scope, elem, attrs){
//obtain old header
var oldHeader = angular.element( '.headerdiv .headerclass' );
//get the new header
//replace old header with new header
}
});
I need to dynamically change the heading in headerdiv with the object.title value . Note that the new directive is bound to the filed that is listening to the object.title div.
I dont think this is the right use of directive, as the directive should be used to affect the functionality of element on which it is defined in most of the cases.
What you can try to do is in ObjectCtrl define a watch on title property, and then broadcast the message
$scope.$watch('object.title',function(newValue) {
$rootScope.$broadcast('titleChanged',newValue); //You can pass any object too
});
If you header is contained inside a controller catch the event
$scope.$on('titleChanged',function(args) {
//Code to handle the title update
});
The html for header should have binding expression for title
<div class="headerdiv">
<h3 class='headerclass'> {{title}} </h3>
</div>
Note: I am not sure about the structure of the html but this all would not be required if the header and the content inside the ObjectCtrl are using the same\shared model (object).
Related
I'm trying to configure the stripe payment element for a custom design
From whay I could see, the only option I have is to use the Elements Appearance API
That's because stripe dinamycally inserts an iframe with the markup (to remain PCI DSS compliant), and that's why I can't find a way to modify it.
Stripe payment element generates the following markup
<div class="p-Grid p-CardForm">
<div class="p-GridCell p-GridCell--12 p-GridCell--md6">
<!-- CardNumberInput -->
</div>
<div class="p-GridCell p-GridCell--6 p-GridCell--md3">
<!-- expiryInput -->
</div>
<div class="p-GridCell p-GridCell--6 p-GridCell--md3">
<!-- cvcInput -->
</div>
</div>
Which uses some custom stripe grid system and produces this:
And above md it displays the following (it's applying the p-GridCell--mdXX classes):
I need to keep the first layout regardless the size of the viewport. How can I disable stripe grids or choose what clases to apply?
Update:
I tried the following approaches to modifiy the classes being applied, with no success:
Use javascript to inject a style tag to the iframe's head:
const iframe = document.getElementsByTagName('iframe')[0]; // this works
const doc = iframe.contentDocument; // woops, this is always null!!!
doc.body.innerHTML = doc.body.innerHTML + '<style>.....' // so I can't do something like this
(taken from this article)
Use javascript to get a reference to the container divs and modify the classes being applied (this approach works in the developer console, only after you inspect the element, but it doesn't work from a javascript block from the html page hosting the iframe)
const numberInput = document.getElementById('Field-numberInput'); // returns null
const numberContainer = document.querySelector('.p-GridCell.p-GridCell--12.p-GridCell--md6'); // also returns null
Following this guide I also tried:
const iframe = document.getElementsByTagName('iframe')[0]; // this works
let y = iframe.contentWindow.document;
y.body.style.backgroundColor = "red";
Which throws the following error:
FormElement.svelte:28 Uncaught DOMException: Blocked a frame with origin "http://localhost:3000" from accessing a cross-origin frame.
at HTMLButtonElement.updateStyle
I dont know stripe-payment css file but maybe changing md6 to md12 and md3 to md6 will work.
<div class="p-Grid p-CardForm">
<div class="p-GridCell p-GridCell--12 p-GridCell--md12">
<!-- CardNumberInput -->
</div>
<div class="p-GridCell p-GridCell--6 p-GridCell--md6">
<!-- expiryInput -->
</div>
<div class="p-GridCell p-GridCell--6 p-GridCell--md6">
<!-- cvcInput -->
</div>
</div>
will work
Say, I'm using often the following HTML in ASP.NET MVC application:
<div class="a">
<div class="b">
(varying content)
</div>
</div>
I'd like to put the repeating div part to a separate file and reuse it (notice, that the content may, and will change). How can I do that?
Keep it in a partialView, eg: _CommonDiv
call Partial view from your view
#Html.Partial("_CommonDiv", null, new ViewDataDictionary {{ "yourvaringcontentKey", yourcontent}})
get content in partialView
string yourcontent= (string)this.ViewData["yourvaringcontentKey"];
And use the same where you want.
In your web application add App_Code\Helpers.cshtml
Paste the code below inside Helpers.cshtml
Helper code:
#helper DivHelper(string text)
{
<div class="a">
<div class="b">
#text
</div>
</div>
}
Now you can call this helper in any of your views using #Helpers.DivHelper("Some text...") and because the logic is inside App_Code no using statements are required!
I am new to polymer & trying to create a configurable template for the received iron-ajax response, means the end user who is using the component can decide the items which need to be displayed in the screen, so I used content tag inside the template but the data is not getting bind with my custom element.
index.html
<custom-element>
<div class="selected_content">
<h2>{{item.id}}</h2>
<span>{{item.member.dept.name}}</span>
</div>
</custom-element>
customElement.html
<iron-ajax
auto
url={{url}}
handle-as="json"
last-response={{lastresponse}}
debounce-duration="300"></iron-ajax>
<template is="dom-repeat" items=[[lastresponse]]>
<content select=".selected_content"></content>
</template>
I'm struggling with fullpage.js in Meteor.
When I add a button inside a template, the Template.templatename.events function does not fire on event.
For example:
Template HTML (messages.html)
<template name="messages">
<ul>
{{#each mess}}
<li>{{ messContent}}</li>
{{/each}}
<button class="addMessage">Add Message!</button>
</ul>
</template>
Template JavaScript (messages.js)
Template.messages.helpers({
mess: function(){
return Messages.find();
}
});
Template.messages.events({
'click .addMessage' : function(event){
console.log("clicked")
}
})
Main HTML
<head>
<title>fulltest</title>
</head>
<body>
{{> full}}
</body>
<template name="full">
<div id="fullpage">
<div class="section active">
<h1>First slide</h1>
{{> messages}}
</div>
<div class="section">
<h1>Second slide</h1>
</div>
</div>
</template>
My fullpage initialisation:
Template.full.rendered = function(){
$('#fullpage').fullpage();
}
If I remove the fullpage initialisation then the click event gets logged. Still new at Meteor, I didn't manage to grasp what's going wrong here.
All help much appreciated,
Joris
Use delegation or use verticalCentered:false and scrollOverflow:false.
From the fullPage.js FAQs:
My javascript/jQuery events don't work anymore when using fullPage.js
Short answer: if you are using options such as verticalCentered:true or overflowScroll:true in fullPage.js initialization, then you will have to treat your selectors as dynamic elements and use delegation. (by using things such as on from jQuery). Another option is to add your code in the afterRender callback of fullpage.js
Explanation: if you are using options such as verticalCentered:true or overflowScroll:true of fullPage.js, your content will be wrapped inside other elements changing its position in the DOM structure of the site. This way, your content would be consider as "dynamically added content" and most plugins need the content to be originally on the site to perform their tasks. Using the afterRender callback to initialize your plugins, fullPage.js makes sure to initialize them only when fullPage.js has stopped changing the DOM structure of the site.
I'm trying to get the following behavior for a certain template:
<body onload="someInitFunction();">
Let's say i have the following markup (i'm using mrt router, not iron-router, for {{renderPage}}):
// Main Template
<head>
<title>meteorite-knowviz</title>
</head>
<body>
{{> header}}
<div class="container-fluid">
<div class="row">
{{renderPage}}
</div>
</div>
{{> footer}}
</body>
That renderPage is the secondTemplate:
<template name="secondTemplate">
{{#if currentUser}}
<div class="col-md-2">
<div class="list-group">
<a class="list-group-item" href="{{render thirdTemplate please...}}">Third Template</a>
<a class="list-group-item" href="{{render fourthTemplate please...}}">Fourth Template</a>
</div>
</div>
// In this case let's say thirdTemplate gets rendered
{{render the choice taken above please...}}
{{/if}}
</template>
And within this template, depending on which link was clicked on, (in this case the third) there will finally be a thirdTemplate, which will show a data visualization with some help by a javascript framework, which will be in need of a <body onload="initFunction();">in order to display the data:
<template name="thirdTemplate">
<div class="col-md-5">
<h2>THIS!! section needs a "<body onload="initFunction();"> in order to work" ></h2>
</div>
<div class="col-sm-5">
<h2>Some other related content here</h2>
</div>
</template>
To sum up i have three questions:
1a. How could i get the third template to get a <body onload="initFunction();">
2a. In which way can i render different templates within the secondTemplate?
2b. Can i use a {{renderPage}} within this template even though this template is the renderedPage in the main template or should i do it in some other way?
In order to get the <body onload="initFunction();"> i had to do the following:
First add the following function to a .js file in the client folder:
Template.thirdTemplate.rendered = function() { // Template.thirdTemplate.created - also worked.
$('body').attr({
onload: 'init();'
});
}
This however got me an error saying that initFunction is not defined. In an standard html page my could work just fine, but in meteor i had to change my function from:
function initFunction(){
//what ever i wished to do
}
To:
init = function() {
//what ever i wished to do
}
Regarding the rendering of pages, iron-routing is the way to go since the router add on is not under development any more.
1a. How could i get the third template to get a <body
onload="initFunction();">
You probably want to call initFunction when the third template has been rendered, so just put your call to it in the rendered callback.
Template['thirsTemplate'].rendered = function(){
initFunction()
}
2a. In which way can i render different templates within the
secondTemplate?
2b. Can i use a {{renderPage}} within this template even though this
template is the renderedPage in the main template or should i do it in
some other way?
Listen for clicks on the links, and when one happen you manually render the desired template (possible with Meteor.render, if you need reactivity) and add it to the right node in the document. See this question.
It may be possibly to achieve with router (I don't know that package).
I think that what you want to use is the created callback, that will be called each time your template is created, and not the rendered callback, that would be called each time a change has caused the template to re-render.
Template.thirdTemplate.created = function(){
initFunction()
}
See the documentation for templates for other types of callbacks: http://docs.meteor.com/#templates_api