Add dynamic html without using compose inside the View - aurelia

I need to add an html div element inside a custom component(footable).
Since the component is constructed at run time, I am not able to use compose anywhere in the html, therefor I must add my elements using jQuery.
Any ideas how can I add the below and bind to a ViewModel's method?
footable event:
'postinit.ft.table':function(e,ft){
$('.footable-filtering .form-inline').append('<div class="form-group"><a
href="#" click.delegate="refreshNow()" class="btn btn-primary"><i class="fa
fa-refresh"></i></a></div>');
}

I'd probably come at it a different way. I'd use jQuery's .on handler to attach a listener to the .footable-filtering element, seeing as it seems that's present from the start;
'postinit.ft.table':function(e,ft){
$('.footable-filtering .form-inline').append('<div class="form-group"><a
href="#" click.delegate="refreshNow()" class="btn btn-primary refreshButton"><i
class="fa fa-refresh"></i></a></div>');
}
$('.footable-filtering').on('click', '.refreshButton', (e) => {
e.preventDefault();
this.refreshNow();
}
This is untested - but should work.
Edt - It's also worth saying that combining Aurelia and jQuery in this way isn't ideal - but as you're using jQuery anyway to create the element it's use is passable.

Related

How can I get css property of an element which clicked in Blazor?

Here is some A elements in blazor server-side:
<div>
<a href="javascript:void(0)" class="Add" #onclick="SingleAddClick">
<a href="javascript:void(0)" class="Add" #onclick="SingleAddClick">
<a href="javascript:void(0)" class="Add" #onclick="SingleAddClick">
<a href="javascript:void(0)" class="Add" #onclick="SingleAddClick">
<a href="javascript:void(0)" class="Add" #onclick="SingleAddClick">
</div>
All the position of the A elements above is absolute. The Left and Top are differing from each A element.
Now when an A element is clicked, I wanna get the Left and Top of its position.
I need to transfer the js object from .Net method to JS method by JS interop while I don't know how to get the JS object in .Net method.
How can I achieve this?
Thank you.
You can capture a reference to your element as follows:
<a #ref="anchorElement" href="javascript:void(0)" class="Add"
#onclick="SingleAddClick">
#code
{
private ElementReference anchorElement;
}
Now you can call a JSInterop method and pass it the element reference. You should use it in your JS method as though it was retrieved by the getElementById method.
Note: You shouldn't use JavaScript in Blazor. Use #onclick:preventDefault instead of href="javascript:void(0)"
I hope that helps! If you get stuck, let me know
In-order to identify left and top, you'll need to provide a unique identifier (uid) to your every anchor tags. Your uid can either be a ElementReference or a just static (hard-coded) name. With this uid you can identity from where the event is raised from then search it in dom to find relative position to the viewport.
Below are the changes you will need to do to get the elements left and top position.
Razor Component
#inject IJSRuntime JSRuntime // need to inject IJSRuntime to invoke a JavaScript function.
<a id="anchor1" href="" class="Add" #onclick='() => SingleAddClick("anchor1")' #onclick:preventDefault>
#code{
private async Task SingleAddClick(string clickedElementId)
{
//your existing code
// call the javacript method that will be returing something.
var dimensions = await JSRuntime.InvokeAsync<string>("getDimensions", clickedElementId);
// I've used a dynamic type object so that I don't need to create a custom class to desealize it.
dynamic d = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(dimensions);
// Since I've used dynamic keyword thus the type will get resolved at runtime.
// Will throw exception if d is null thus need to be handled properly.
string top = d.top;
string left = d.left;
}
}
JS Library
If you are using any existing js file for interop service then add below javascript method else create a new js file and reference it in _host.
function getDimensions(element) {
return JSON.stringify(document.getElementById(element).getBoundingClientRect());
}
Note: The getBoundingClientRect() method returns the size of an element and its position relative to the viewport.

How to combine aurelia-materialize-bridge and sweetalert2

I want to put a form in a popup.
I've found a solution but I'm looking for something cleaner.
I didn't find a way to poping-up an existing tag with swal.
So I created an hidden form in my template :
<div id="myHiddenForm"><form role="form">
<md-input class="email" md-type="email" md-label="Email" md-validate="true"
md-validate-error="invalid email">
<i md-prefix class="material-icons">account_circle</i>
</md-input>
<button type="submit" md-button>
<i class="left material-icons">done</i>Submit
</button>
</form></div>
Then I created the popup with it's innerHTML.
swal({
html: document.getElementById('myHiddenForm').innerHTML,
showConfirmButton: false,
}).catch(swal.noop);
Then I can attach a callback to the submit button and this works finally.
Obviously, I can't use md-value.bind because the displayed form is a copy of the original.
I can access the input's value, using document.querySelectorAll('#myHiddenForm .email input')[0].value but I'm wondering if there's a better way to do this ?
Maybe there's a nice approach to combine aurelia-materialize-bridge and sweetalert2.
I know there's a modal component but it's not capable of keeping the focus inside the modal popup ; plus I already use swal2 everywhere else in this webapp because, you know, it is so sweet.
After a lot of tests and the full reading of the sweetalert2 documentation, I found the correct way to handle this. We simply need to move the <form> node.
swal({
html: '<span></span>'
, showCloseButton: true
, showConfirmButton: false
, onBeforeOpen: dom => swal.getContent()
.appendChild(document.querySelectorAll('#myHiddenForm form'))
, onClose: dom => document.getElementById('myHiddenForm')
.appendChild(swal.getContent().querySelectorAll('form'))
}).catch(swal.noop);
It's perfect to use with aurelia because it preserve everything (monitors, events, validation...).
We don't even need to manually bind the submit button like I did, We can use aurelia's usual way.
Conclusion: RTFM !

angular-file-upload - how to make drop zone clickable?

Using nv-file-upload (https://github.com/nervgh/angular-file-upload) how can I make the drop zone act also as a clickable element to select files? Adding {{nv-file-select}} does not seem to work.
The answer is that YOU CANT, there is no way to do this inside that plugin but i use a simple solution for this kind of problems. Add a ng-click inside your dragNdrop tag and call your function:
<div nv-file-drop="" uploader="upload" ng-click="launchFilePicker()">
<div class="drop-box" ng-show="upload.isHTML5" uploader="upload" nv-file-over="" over-class="dragover" filter="image/*,application/pdf">
Drag a file here.
</div>
</div>
<div ng-hide="upload.isHTML5"> <input id="fileDialog" type="file" nv-file-select uploader="upload"/><br/></div>
And inside your controller you do this:
$scope.launchFilePicker = function () {
//$('#fileDialog').click(); //not angular way
angular.element('#fileDialog').trigger('click'); //angular way
};
I hope this help.

Durandal: Showing a 'LOADING...' during composition

I can easily show a loading message while the activate method is doing its thing like so:
<div data-bind="compose:ActiveVm">
<div class="text-center" style="margin : 75px">
<i class="fa fa-spinner fa-spin"></i>
</div>
</div>
However if I then update my ActiveVm property with a different viewmodel, the splash content does not show. I understand that the splash content is only designed to show on 'initial' load, but what options do I have for displaying such a message when transitioning from one viewmodel to another?
Note that this composition does not participate in routing...
Update: Related durandal issue here which might be of value to future visitors: https://github.com/BlueSpire/Durandal/issues/414
This begs for a comment of 'what have you tried?' but given that I could see the benefit of this for future users I wanted to throw in my $0.02 -
The splash displays on your screen until Durandal loads up the application and replaces the div with id="applicationHost" 's content with the shell view and the subsequent views that are loaded. If you wanted to make this a re-usable component one thing that you could do is to take that Html.Partial view that is being loaded and create your own view inside of your app folder in your Durandal project.
For example you would create a new HTML view inside of your app folder -
splashpage.html
<div class="splash">
<div class="message">
My app
</div>
<i class="icon-spinner icon-2x icon-spin active"></i>
</div>
And then compose it from your shell -
<div data-bind="if: showSplash">
<!-- ko compose: 'splashpage.html' -->
<!-- /ko -->
</div>
And in your view model you would toggle the observable showSplash whenever you want to show / hide it -
var showSplash = ko.observable(false);
var shell = {
showSplash: showSplash
};
return shell;
And you could call that from your activate methods inside your other view models like this -
define(['shell'], function (shell) {
function activate() {
shell.showSplash(true);
// do something
shell.showSplash(false);
}
});
This sounds to me like a scenario where a custom transition may be useful. When the composition mechanism switches nodes in and out of the DOM, it can use a transition.
This page, under Additional Settings>Transition (about halfway down) describes a custom transition: http://durandaljs.com/documentation/Using-Composition/

JavaScript .innerHTMLworking only when called manually

I've got a very simple function, of replacing the innerHTML of a element. I've been trying to debug this for hours but simply can't, and it's infuriating.
When called from a button press the JavaScript (as follows) works well, but when called from another function it doesn't work. I am totally lost as to why this might be, and its a fairly core part of my app
// This loaded function in my actual code is a document listener
// checking for when Cordova is loaded which then calls the loaded function
loaded();
function loaded() {
alert("loaded");
changeText();
}
function changeText() {
alert("started");
document.getElementById('boldStuff').innerHTML = 'Fred Flinstone';
}
Button press and HTML to replace
<div id="main">
<input type='button' onclick='changeText()' value='Change Text'/>
<p>Change this text >> <b id='boldStuff'> THIS TEXT</b> </p>
</div>
It is also here in full on JSFiddle
You are already changed the innerHTML by calling the function loaded(); on onLoad.
Put this in an empty file and same as .html and open with browser and try. I have commented the function loaded();. Now it will be changed in onclick.
<div id="main">
<input type='button' onclick='changeText();' value='Change Text'/>
<p>Change this text >> <b id='boldStuff'> THIS TEXT</b> </p>
</div>
<script>
//loaded();
function loaded() {
alert("loaded");
changeText();
}
function changeText() {
alert("started");
document.getElementById('boldStuff').innerHTML = 'Fred Flinstone';
}
</script>
The problem here is, that the element you're trying to manipulate is not yet existing when you are calling the changeText() function.
To ensure that the code is only executed after the page has finished loading (and all elements are in place) you can use the onload handler on the body element like this:
<body onload="loaded();">
Additionally you should know, that it's very bad practice to manipulate values by using the innerHTML property. The correct way is to use DOM Manipulations, maybe this can help you.
You script loads before the element (boldStuff) is loaded,
Test Link - 1 - Put the js in a seperate file
Test Link - 2 - put the js at the very end, before closing the <body>