Passing Data to modal / WebView - nativescript-vue

In NativeScript-Vue, what's the simple, clean way to pass data to a modal?
Background:
I need to display external web pages in a modal. WebView seems the thing. Except that the docs indicate that you must hard code the source:
<WebView src="http://nativescript-vue.org/" />
That's no good. I need something like
<WebView :src="myUrl" />
data() {
return {
myUrl: "https://en.wikipedia.org/wiki/Mary,_Queen_of_Scots",
}
Despite what the documentation says, this seems to work. Yay!!
Now, in the modal, how do I set myUrl to a value from the original app page?

From you original page:
this.$showModal(YourWebModal, {
props: {
myUrl: 'https://en.wikipedia.org/wiki/Mary,_Queen_of_Scots'
}
})
In your modal:
<WebView :src="myUrl" />
props: ['myUrl'],
data () {
return {}
}

Related

jwPlayer causes rendering not to load in Sitecore's Page Editor

I'm currently working on a rendering in Sitecore 7.2 (MVC) that will show a jwPlayer given a link to a video (either in the Media Library or from an external source, like YouTube). When I add the rendering (with a valid data source) through Presentation Details in the Content Editor everything looks fine, and works perfectly. The trouble that I'm running into right now, though, is that when I try to do the same thing from the Page Editor (with the exact same rendering and data source), nothing is showing up in that placeholder at all.
The part of the rendering that deals with the video is as follows:
#if (Model.VideoLink != null && Model.Image != null)
{
var vidid = Guid.NewGuid().ToString();
<div class="article-video-module">
<p class="video-placeholder-text">#Html.Raw(Model.Heading)</p>
<div id="#vidid">Loading the player...</div>
<script type="text/javascript">
jwplayer("#vidid").setup({
file: "#Model.VideoLink.Url",
image: "#Model.Image.Src",
width: "100%",
aspectratio: "16:9",
sharing: {
link: "#Model.VideoLink.Url"
},
primary: 'flash'
});
jwplayer('videodiv-#vidid').onPlay(function () {
$(this.container).closest('.fullbleed-video-module').find('.video-placeholder-text').hide();
});
jwplayer('videodiv-#vidid').onPause(function () {
$(this.container).closest('.fullbleed-video-module').find('.video-placeholder-text').show();
});
</script>
</div>
#Editable(a => Model.Description)
}
Other things that might help:
When I comment out everything in the <script> tag above the rendering shows up perfectly.
A reference to jwplayer.js is found on the page (that was my first thought)
Console errors in Javascript:
No suitable players found and fallback enabled on jwplayer.js
Uncaught TypeError: undefined is not a function on jwplayer("#vidid").setup({ and on jwplayer('videodiv-#vidid').onPlay(function () { from above.
How can I get jwPlayer and Page Editor to work nicely with each other?
The issue is that when you add a component through Page Editor, the script is fired before the div <div id="#vidid"> element is added to DOM. Don't ask me why...
The solution is really simple: wrap your javascript code with if condition, checking if the div is already there:
<script type="text/javascript">
if (document.getElementById("#vidid")) {
jwplayer("#vidid").setup({
file: "#Model.VideoLink.Url",
image: "#Model.Image.Src",
width: "100%",
aspectratio: "16:9",
sharing: {
link: "#Model.VideoLink.Url"
},
primary: 'flash'
});
jwplayer('videodiv-#vidid').onPlay(function () {
$(this.container).closest('.fullbleed-video-module').find('.video-placeholder-text').hide();
});
jwplayer('videodiv-#vidid').onPause(function () {
$(this.container).closest('.fullbleed-video-module').find('.video-placeholder-text').show();
});
}
</script>
There is also another issue with your code - Guid can start with number, and this is not a valid id for html elements. You should change your code to:
var vidid = "jwp-" + Guid.NewGuid().ToString();
I wouldn't rule out a conflict with the version of JQuery that the Page Editor uses - this usually messes stuff up. There's a good post here on to overcome the issues.
http://jrodsmitty.github.io/blog/2014/11/12/resolving-jquery-conflicts-in-page-editor/

Emberjs outlet inside a bootstrap popover

I'm using bootstrap popover in my app and I need to render an outlet inside it.
I have this nested route :
this.resource('pages', function(){
this.resource('page', { path: ':id' }, function(){
this.resource('edit', function(){
this.resource('images', function(){
this.resource('image', { path: ':image_id'}, function(){
this.route('edit');
})
});
});
});
});
When the user is here => /pages/1/edit/ when he click on an image it route to /images but render the {{outlet}} inside the popover like this :
<div class="popover-content hide">
{{outlet}}
</div>
This is my popover initialisation :
$img.popover({
html: true,
content: function() {
return $('.popover-content').html(); //need to have the outlet here
}
});
So far, it render correctly my outlet, but inside the images template, I have some button that modify the DOM and it doesn't update the html. Unless if I close and open the popover again I can see the modification.
Is it possible to render the outlet directly inside the code ? or is it possible to have my popover being updated ?
Thanks for the help.
See these links for an alternative approach to putting Ember stuff in Bootstrap popovers:
Bootstrap Popovers with ember.js template
https://cowbell-labs.com/2013-10-20-using-twitter-bootstrap-js-widgets-with-ember.html
Ember and Handlebars don't like this because it's basically copying the html content of a div and plopping it into another. But that html alone isn't everything that's needed. Ember is magic and there's lots of stuff happening in the background.
Your hidden div is real ember stuff, so let's try not to mess with it by calling .html() on it. My idea is to literally move the DOM itself instead.
first, modify your popover function call to always create this placeholder div:
content: '<div id="placeholder"></div>',
next, detach the content div from the dom in the didInsertElement of the view:
// get the popover content div and remove it from the dom, to be added back later
var content = Ember.$('.popover-content').detach();
// find the element that opens your popover...
var btn = Ember.$('#btn-popup-trigger').get(0);
// ... and whenever the popover is opened by this element being clicked, find the placeholder div and insert the content element
// (this could be improved. we really just want to know when the popover is opened, not when the button is clicked.)
btn.addEventListener("click", function() {
content.appendTo("#placeholder");
});
since the content div is immediately detached when didInsertElement is called, you can remove the "hide" css class from the content div.
edit: i tried this on my own project and it broke two-way binding. the controller updated my handlebars elements, but any two-way bound {{input}} helpers did not update the controller/model. i ended up using a single-item dropdown menu, and used this to prevent the menu from closing too quickly:
Twitter Bootstrap - Avoid dropdown menu close on click inside

How to make react.js play nice together with zurb reveal modal form

I am trying to integrate zurb reveal with form into react component. So far next code properly displays modal form:
ModalForm = React.createClass({
handleSubmit: function(attrs) {
this.props.onSubmit(attrs);
return false;
},
render: function(){
return(
<div>
Add new
<div id="formModal" className="reveal-modal" data-reveal>
<h4>Add something new</h4>
<Form onSubmit={this.handleSubmit} />
<a className="close-reveal-modal">×</a>
</div>
</div>
);
}
});
The Form component is pretty standard:
Form = React.createClass({
handleSubmit: function() {
var body = this.refs.body.getDOMNode().value.trim();
if (!body) {
return false;
}
this.props.onSubmit({body: body});
this.refs.body.getDOMNode().value = '';
return false;
},
render: function(){
return(
<form onSubmit={this.handleSubmit}>
<textarea name="body" placeholder="Say something..." ref="body" />
<input type="submit" value="Send" className="button" />
</form>
);
}
});
Problem: When I render form component within modal form component and enter something into form input then I see in console exception Uncaught object. This is a stack:
Uncaught object
invariant
ReactMount.findComponentRoot
ReactMount.findReactNodeByID
getNode
...
If I just render form component directly in the parent component then everything works. Could anybody help please?
In short, you're doing this wrong and this is not a bug in react.
If you use any kind of plugin that modifies the react component's dom nodes then it's going to break things in one way or another.
What you should be doing instead is using react itself, and complementary css, to position the component in the way you'd like for your modal dialog.
I would suggest creating a component that uses react's statics component property to define a couple of functions wrapping renderComponent to give you a nice clean function call to show or hide a react dialog. Here's a cut down example of something I've used in the past. NB: It does use jQuery but you could replace the jQ with standard js api calls to things like elementById and etc if you don't want the jQuery code.
window.MyDialog = React.createClass({
propTypes: {
title: React.PropTypes.string.isRequired,
content: React.PropTypes.string.isRequired
},
statics: {
// open a dialog with props object as props
open: function(props) {
var $anchor = $('#dialog-anchor');
if (!$anchor.length) {
$anchor = $('<div></div>')
.prop('id', 'dialog-anchor');
.appendTo('body');
}
return React.renderComponent(
MyDialog(props),
$anchor.get(0)
);
},
// close a dialog
close: function() {
React.unmountComponentAtNode($('#dialog-anchor').get(0));
}
},
// when dialog opens, add a keyup event handler to body
componentDidMount: function() {
$('body').on('keyup.myDialog', this.globalKeyupHandler);
},
// when dialog closes, clean up the bound keyup event handler on body
componentWillUnmount: function() {
$('body').off('keyup.myDialog');
},
// handles keyup events on body
globalKeyupHandler: function(e) {
if (e.keyCode == 27) { // ESC key
// close the dialog
this.statics.close();
}
},
// Extremely basic dialog dom layout - use your own
render: function() {
<div className="dialog">
<div className="title-bar">
<div className="title">{this.props.title}</div>
<a href="#" className="close" onClick={this.closeHandler}>
</div>
</div>
<div className="content">
{this.props.content}
</div>
</div>
}
});
You then open a dialog by calling:
MyDialog.open({title: 'Dialog Title', content: 'My dialog content'});
And close it with
MyDialog.close()
The dialog always attaches to a new dom node directly under body with id 'dialog-anchor'. If you open a dialog when one is already open, it will simply update the dom based on new props (or not if they're the same).
Of course passing the content of the dialog as a props argument isn't particularly useful. I usually extend below to either parse markdown -> html for the content or get some html via an ajax request inside the component when supplying a url as a prop instead.
I know the above code isn't exactly what you were looking for but I don't think there's a good way to make a dom-modifying plugin work with react. You can never assume that the dom representation of the react component is static and therefore it can't be manipulated by a 3rd party plugin successfully. I honestly think if you want to use react in this way you should re-evaluate why you're using the framework.
That said, I think the code above is a great starting point for a dialog in which all manipulation occurs inside the component, which afterall is what reactjs is all about!
NB: code was written very quickly from memory and not actually tested in it's current form so sorry if there are some minor syntax errors or something.
Here is how to do what Mike did, but using a zf reveal modal:
var Dialog = React.createClass({
statics: {
open: function(){
this.$dialog = $('#my-dialog');
if (!this.$dialog.length) {
this.$dialog = $('<div id="my-dialog" class="reveal-modal" data-reveal role="dialog"></div>')
.appendTo('body');
}
this.$dialog.foundation('reveal', 'open');
return React.render(
<Dialog close={this.close.bind(this)}/>,
this.$dialog[0]
);
},
close: function(){
if(!this.$dialog || !this.$dialog.length) {
return;
}
React.unmountComponentAtNode(this.$dialog[0]);
this.$dialog.foundation('reveal', 'close');
},
},
render : function() {
return (
<div>
<h1>This gets rendered into the modal</h1>
<a href="#" className="button" onClick={this.props.close}>Close</a>
</div>
);
}
});

Angular SubViews/Multi-region templating, Directives and Dynamic Template URL

I'm trying to set up a page with two "view areas", one with the standard ng-view that the framework automatically handles, and a custom view area to have another part of the page change-out with the change in view. I figured I could/should do this with directives, but I'm pretty new to Angular and having trouble getting it to work.
So, for example if I have:
<body>
<div class="fixed-menu">
<nav>this never changes</nav>
<fixed-menu-view></fixed-menu-view> <!-- this need to change with ng-view -->
</div>
<div class="content" ng-view> <!-- this changes with an update to the location/routeProvider -->
</div>
</body>
The ng-view is already handled by Angular, but I need a segmented template with another part of the page updated as well, so I'm trying this but not sure how to pass in the routeProvider to get the current "page".
directive('fixedMenuView', function () {
// Can't seem to pass in $scope or $routeProvider here
return {
restrict: 'E',
replace: true,
templateUrl: //computed from the current scope or routeprovider url,
link: function (scope, element, attrs) {
}
}
});
Is there a better way to do this, or what can I do here to accomplish what I'm trying?
I would prefer to use event message instead of the route parsing for two reasons:
you are making a dependency with your url.
you will be able to only display the information defined in the URL
I suggest another solution based on event. First define some event listeners in your navigation bar controller:
$scope.$on('logout', function() {
$scope.setLoggedOutBar();
});
$scope.$on('login', function() {
$scope.setLoggedInBar();
});
$scope.$on('changeSelectedApp', function() {
$scope.changeSelectedApp(myContextService.getSelectedApp());
});
Then in your nested view controller you can spread the event:
$scope.$on('$routeChangeSuccess', function () {
myContextService.setSelectedApp('main');
$rootScope.$broadcast('changeSelectedApp');
});
One of the benefit of this solution is that other components can catch the event and update their contents.
You can pass the route service into the directive through dependency injection. This is also how you are able to inject any other additional services etc.
There is a little more information in the docs, but unfortunately not too many decent examples: http://docs.angularjs.org/guide/di
Once injected, you can access the current route with $route.current: http://docs.angularjs.org/api/ng.$route
directive('fixedMenuView', ['$route', function ($route) {
// Can't seem to pass in $scope or $routeProvider here
return {
restrict: 'E',
replace: true,
templateUrl: //computed from the current scope or routeprovider url,
link: function (scope, element, attrs) {
// Do something with $route.current here
}
}
});
In your case, I would create a 'shell' template for the directive, with either switches inside depending on the current route, or possibly ng-include, if you have a large number of routes to accommodate etc.

How can I know when a Backbone View template is finished rendering?

I'm using Backbone.js, Require.js, and Underscore.js for a single page site.
I have a container view that handles the swapping in and out of sub-views.
For one of my sub-view, I need to know when the rendering of the HTML template is finished. Here's why: My html template for the sub-view (view_subview.html) contains an iframe and a form:
<iframe name="myIFrame" id="myIFrame"></iframe>
<form action="http://myendpt.com/do" method="get" id="myForm" target="myIFrame">
<input type="hidden" name="param1" value="value1"/>
</form>
By submitting the form, the myendpt.com/do will handle generating the content to be displayed in the iframe.
I'm trying to figure out the timing of things so that I can submit the form once it has been loaded.
My sub-view looks like this:
define([
'jQuery',
'Underscore',
'Backbone',
'config',
'text!templates/view_subview.html'
], function ($, _, Backbone, Config, tpl) {
var SubView = Backbone.View.extend({
template: _.template(tpl),
initialize: function () {
},
render: function (eventName) {
$(this.el).html(this.template({config: Config}));
$('#myForm').submit();
return this;
},
});
return SubView;
});
The $('#myForm').submit() call in render() doesn't actually submit the form. Presumably this is because the HTML is still loading and the document is not yet ready.
If I move the $('#myForm').submit() call out to my container view, I can make it work, but I'd like SubView to own the submit of the form. My container view (and other, unrelated sub-views) should not need to know or care about what happens in SubView.
What's the best way to detect in SubView (and only in SubView) that the HTML is fully loaded so that I can call the submit?
Why don't you fire an event when your iframe is loaded and ready? your render function can bind to that event; something alone the lines of:
render: function(eventName){
$(this.el).html(this.template({config:Config})
.bind('formReady',function(){
$('#myForm',this.el).submit();
})
return this;
}
and, just make your iframe fire the event onload:
<iframe onload='$(this).trigger('formReady');' .... >