Share Angular Expression with onclick Function - javascript

Let me try explaining things again. I have an app running in a javascript framework on Node.js w/ Bootstrap. In one of the bootstrap panels I embedded an Angular Elasticsearch search client. Here's some code that displays the results:
<section class='results'><article class='result' ng-repeat='result in results track by $id(result)' /><div id="addThisInfo" ng-repeat='ng-repeat='result in results track by $id(result)' style="display: none;"> {{$id}},{{result.code}},{{result.expression}},{{result.source}}</div>Code:{{result.code}}<br>Description: {{result.expression}}<br>div ng-if='result.source ==4'> Type: Source 1</div><div ng-if='result.source ==10'> Type: Source 2</div></article> </section>
There are 5 results per page.
Note that the only portion of this app written in Angular is this search mechanism.
Ultimately I want the user to be able to click on either the text of the desired result or click on a button that would add their choices to a separate table.
Here's how it works rignt now. When I click on any of the 5 results per page it invokes this:
document.addEventListener("click", function() {
var packy = document.getElementById("addThisInfo").innerHTML; //div above
addInfo(packy);
});
It doesn't matter which ever one of the results I click, it always sends the "first" result of the active page. Even though the div "addThisInfo" has been repeated and is part of the result, it doesn't
The web socket call looks something like this:
{"params":"0ij,I77.812ZZ,"Full Expression","100"}
I'm not having any luck uploading an image of the Inspect Element. But there you can see that all of the data is there.
I'd like to schedule a http://join.me session with someone so I could show you how it's currently working. Help is greatly appreciated!!
Thanks!

why must you pass them individually? I'm unsure of what you're trying to accomplish, exactly, but I'd handle it something like this:
for the markup:
<button ng-click="addInfo(result)">
then in the controller
$scope.addInfo = function(result) {
var foo = result.code,
bar = result.source;
etc...
}

Angular. directive('notNgClick', function () { return {
restrict: 'A',
scope: {
values: '&'
},
link: function (scope,elem, attr) {
elem.addEventListener(function () {alert (scope.values.someValue ) } )
}
}
}

Related

How Can I Pass String Variable to Anonymous Adobe View SDK Script?

I have a very basic knowledge of javascript and I have been unable to find a solution for my specific use of the Adobe View SDK API, though it seems like there should be a way. I am working on a web page to show newsletters in the pdf viewer. I have created a w3.css modal element so that I can open the viewer with a button click, and then close it with an "x" in the corner. The button click and the "x" toggle between the display style being "none" or "block". I really like this solution as it lets me use small images of the newsletters as the buttons, and it can be observed here: Test News Page by clicking on the newsletter image below May 4, 2020.
The ultimate goal I have is to be able to change the name of the pdf document that is opened in the viewer by clicking the button, which would need to pass a string variable called "docName" to the url called by the View SDK script. Since the url is already specified in the script inside my modal element when the page loads, here is the thinking I have for the additional script I need to pass my string variables: The button-click invokes my script (function changeName(docName)) and passes the "docName" variable. Then my script needs to pass this variable to the url in the View script (this is the part I don't know how to do), then refresh the page to reload my modal, and then change the display style of the modal to "block". I will copy the code for the View SDK below, showing where I need to insert the string variable with my document name:
<script src="https://documentcloud.adobe.com/view-sdk/main.js"></script>
<script type="text/javascript">
document.addEventListener("adobe_dc_view_sdk.ready", function(){
var adobeDCView = new AdobeDC.View({clientId: "06179511ab964c9284f1b0887eca1b46", divId: "adobe-dc-view"});
adobeDCView.previewFile({
content:{location: {url: "https://www.shcsfarmington.org/" + docName + ".pdf"}},
metaData:{fileName: "Newsletter_050420.pdf"}
}, {embedMode: "FULL_WINDOW", defaultViewMode: "FIT_WIDTH"});
});
</script>
It seems like this should work, but with my limited knowledge of javascript I don't know how to pass this variable to the anonymous function in the View SDK code, and I would need as much detail and specifics in the syntax of the solution. I appreciate any help with this. Thanks.
EDIT: I thought maybe it would help to show the code for the function that I have come up with so far - then it could be examined and easier to debug and comment on:
<button id="CSS-050420" onclick="changeDoc('Newsletter_050420');"></button>
<script>
function changeDoc(docName) {
/* Need to pass docName to url=https://shcsfarmington.org/2020/news/Newsletter_" + newsDate + ".pdf"; */
window.location.reload(true);
document.getElementById('viewerModal').style.display='block';
}
</script>
I created a CodePen here for you to look at.
Basically, you'll load the first file when the SDK is ready but then you need to set the adobeDCView to null before recreating it.
function showPDF(url) {
adobeDCView = null;
fetch(url)
.then((res) => res.blob())
.then((blob) => {
adobeDCView = new AdobeDC.View({
// This clientId can be used for any CodePen example
clientId: "e800d12fc12c4d60960778b2bc4370af",
// The id of the container for the PDF Viewer
divId: "adobe-dc-view"
});
adobeDCView.previewFile(
{
content: { promise: Promise.resolve(blob.arrayBuffer()) },
metaData: { fileName: url.split("/").slice(-1)[0] }
},
{
embedMode: "FULL_WINDOW",
defaultViewMode: "FIT_PAGE",
showDownloadPDF: true,
showPrintPDF: true,
showLeftHandPanel: false,
showAnnotationTools: false
}
);
});
}
The link click even will pass the url to the PDF and then display it.

Set ng-disabled parameter to button in $ionicPopup

I'm trying to create a $ionicPopup where one of the buttons is disabled under certain conditions (being the return value of a function, let's call it MyFunction()). I want to use ng-disabled for this purpose.
The problem is, I don't know how to programmatically add the attribute "ng-disabled".
What I tried so far:
Adding the attribute when creating the popup, like attr:"ng-disabled='myFunction()'"
Adding the attribute after the popup was created, using JavaScript => The problem is that the setAttribute() method is executed before the popup is actually shown, so I would need a way to detect when the popup is open, and execute the method only then.
Creating the button as html elements inside the popup template, and not setting any button with the $ionicPopup.show() method. This works, but I'm not satisfied with it because I don't want to "reinvent the wheel" and redefine CSS styles for buttons that are already covered by Ionic framework.
My JS function:
$scope.displayPopUp=function(){
var alertPopup = $ionicPopup.show({
templateUrl: 'sharePopUp.html',
title: 'Invite a friend',
cssClass: 'popupShare',
buttons:[
{
text:'Close',
type: 'button-round button-no',
onTap: function(){
/* Some instructions here */
}
},
{ /* v THIS IS THE BUTTON I WANT TO DISABLE UNDER CERTAIN CONDITIONS v */
text:'Share',
type: 'button-round button-yes',
onTap: function(){
/* Some instructions here */
}
}
]
});
$(".button-yes")[0].setAttribute("ng-disabled", "MyFunction()"); /* NOT WORKING BECAUSE button-yes IS NOT EXISTING YET */
}
TL;DR
$timeout(function () { // wait 'till the button exists
const elem = $('.button-yes')[0];
elem.setAttribute('ng-disabled', 'MyFunction()'); // set the attribute
$compile(elem)(angular.element(elem).scope()); // Angular-ify the new attribute
});
Live demo: working plunk
Introduction
That problem you're encountering, it's a real one, and it has apparently been for years.
Here's the latest version of the code used by $ionicPopup (last updated in December 2015)
This template is the one used by your Ionic-1 popups (from the first lines of the code linked above):
var POPUP_TPL =
'<div class="popup-container" ng-class="cssClass">' +
'<div class="popup">' +
'<div class="popup-head">' +
'<h3 class="popup-title" ng-bind-html="title"></h3>' +
'<h5 class="popup-sub-title" ng-bind-html="subTitle" ng-if="subTitle"></h5>' +
'</div>' +
'<div class="popup-body">' +
'</div>' +
'<div class="popup-buttons" ng-show="buttons.length">' +
'<button ng-repeat="button in buttons" ng-click="$buttonTapped(button, $event)" class="button" ng-class="button.type || \'button-default\'" ng-bind-html="button.text"></button>' +
'</div>' +
'</div>' +
'</div>';
There's one line in particular that's interesting to us: the button template:
<button ng-repeat="button in buttons" ng-click="$buttonTapped(button, $event)" class="button" ng-class="button.type || \'button-default\'" ng-bind-html="button.text"></button>
As you can see, there's just no built-in way to alter its button's attributes.
Two approaches
From here, you've got two fixes:
We can contribute to their project on GitHub, implement the missing functionality, write the tests for it, document it, submit an issue, a Pull Request, ask for a newer version to be released and use the newer version.
This is the ideal solution, 'cause it fixes everyone's problems forever. Although, it does take some time. Maybe I'll do it. Feel free to do it yourself though, and tag me, I'll +1 your PR 👍
Write a dirty piece of code that monkey-patches your specific problem in your specific case
This isn't ideal, but it can be working right now.
I will explore and expand on the (quick 'n dirty) option #2 below.
The fix
Of the 3 things you've tried so far:
the first one is simply not a thing (although it could be if we implement it, test it, document it and release it)
the third one is rather unmaintainable (as you know)
That leaves us with the second thing you mentioned:
Adding the attribute after the popup was created, using JavaScript
The problem is that the setAttribute() method is executed before the popup is actually shown, so I would need a way to detect when the popup is open, and execute the method only then.
You're right, but that's only part one of a two-fold problem.
Part 1: The button isn't created yet
Actually, you can delay that call to setAttribute to later, when the popup is shown. You wouldn't wanna delay it by any longer than would be noticeable by a human, so you can't reasonably go for anything longer than 20ms.
Would there be some callback when the popup is ready, we could use that, but there isn't.
Anyways, I'm just teasing you: JavaScript's "multi-tasking" comes into play here and you can delay it by 0 millisecond! 😎
In essence, it has to do with the way JS queues what it has to do. Delaying the execution of a piece of code by 0ms puts it at the end of the queue of things to be done "right away".
Just use:
setTimeout(function () {
$(".button-yes")[0].setAttribute("ng-disabled", "MyFunction()");
}, 0); // <-- 0, that's right
And you're all set!
Well, you do have a button whose ng-disabled attribute indeed is "MyFunction()". But it's not doing anything...
So far, you simply have an HTML element with an attribute that doesn't do anything for a simple HTML button: Angular hasn't sunk its teeth into your new DOM and hooked itself in there.
Part 2: Angular isn't aware of the new attribute
There's a lot to read here about this, but it boils down to the following: Angular needs to compile your DOM elements so that it sets things in motion according to your Angular-specific attributes.
Angular simply hasn't been made aware that there's a new attribute to your button, or that it should even concern itself with it.
To tell Angular to re-compile your component, you use the (conveniently named) $compile service.
It will need the element to compile, as well as an Angular $scope to compile it against (for instance, MyFunction probably doesn't exist in your $rootScope).
Use it once, like so:
$compile(/* the button */ elem)(/* the scope */ scope);
Assuming the following element is your button:
const elem = $(".button-yes")[0];
... you get its actual scope through its corresponding Angular-decorated element thingy:
const scope = angular.element(elem).scope();
So, basically:
const elem = $('.button-yes')[0];
elem.setAttribute('ng-disabled', 'MyFunction()');
$compile(elem)(angular.element(elem).scope());
Tadaaa! That's it! 🎉
... sort of. Until there's some user interaction that would alter the corresponding $scope, the button is actually not even displayed.
Bonus Part: Avoid $scope.$apply() or $scope.$digest()
Angular isn't actually magically picking up things changing and bubbling it all to the right places. Sometimes, it needs to explicitly be told to have a look around and see if the elements are in sync with their $scope.
Well, more specifically, any change that happens asynchronously won't be picked up by itself: typically, I'm talking about AJAX calls and setTimeout-delayed functions. The methods that are used to tell Angular to synchronise scopes and elements are $scope.$apply and $scope.$digest... and we should thrive on avoiding them :)
Again, there's lots of reading out there about that. In the meantime, there's an Angular service (again), that can (conceptually, it's not the literal implementation) wrap all your asynchronous code into a $scope.$apply() -- I'm talking about $timeout.
Use $timeout instead of setTimeout when you will change things that should alter your DOM!
Summing it all up:
$timeout(function () { // wait 'till the button exists
const elem = $('.button-yes')[0];
elem.setAttribute('ng-disabled', 'MyFunction()'); // set the attribute
$compile(elem)(angular.element(elem).scope()); // Angular-ify the new attribute
});
Live demo: working plunk
I think in ionic v1 Ionic Framework team have not implemented this yet as per (Oct 6, '14 10:49 PM). I think still situation is same. But there is a work around for that.
Option 1:
What I understand from your question, your main purpose is to prevent user to click on buttonDelete ionicPopup buttons and perform some instructions until MyFunction() returns truecreate your own template with buttons which you can fully control them. Below is code:
You can achieve this inside onTap :. Here you can add condition of your MyFunction() like below:
JavaScript:
// Triggered on a button click, or some other target
$scope.showPopup = function() {
// Enable/disable text"Share" button based on the condition
$scope.MyFunction = function() {
return true;
};
//custom popup
var myPopup = $ionicPopup.show({
templateUrl: 'Share'"popup-template.html",
typetitle: 'button-round"Invite button-yes'a friend",
onTapscope: function(e)$scope
{ });
// close popup on Cancel ifbutton (MyFunctionclick
$scope.closePopup = function()) {
myPopup.close();
};
};
HTML:
/*<button Someclass="button instructionsbutton-dark" hereng-click="showPopup()">
*/ show
</button>
}<script elseid="popup-template.html" {type="text/ng-template">
<p>Share button is disabled if condition not /satisfied</don'tp>
allow the user to<button performclass="button unlessbutton-dark" MyFunctionng-click="closePopup()"> returns
true Cancel
</button>
e.preventDefault<button class="button button-dark" ng-disabled="MyFunction(); == true">
}Share
}</button>
}</script>
Working example here Here is working codepen snippet:
https://codepen.io/anon/pen/bvXXKG?editors=1011
Option 2:
Delete ionicPopup buttons and create your own template with buttons which you can fully control them. Below is code:
JavaScript:
// Triggered on a button click, or some other target
$scope.showPopup = function() {
// Enable/disable "Share" button based on the condition
$scope.MyFunction = function() {
return true;
};
//custom popup
var myPopup = $ionicPopup.show({
templateUrl: "popup-template.html",
title: "Invite a friend",
scope: $scope
});
// close popup on Cancel button click
$scope.closePopup = function() {
myPopup.close();
};
};
HTML:
<button class="button button-dark" ng-click="showPopup()">
show
</button>
<script id="popup-template.html" type="text/ng-template">
<p>Share button is disabled if condition not satisfied</p>
<button class="button button-dark" ng-click="closePopup()">
Close
</button>
<button class="button button-dark" ng-disabled="MyFunction() == true">
Share
</button>
</script>
Here is working codepen snippet:
https://codepen.io/anon/pen/qYEWmY?editors=1010
Note: Apply your own styles/button's alignment etc
I hope it will help you.

Partial view with Javascript

I have a drop down list (telerik dropdownlist) and for every option i call a different partial view from my controller.
onChange = function (e)
{
var product = e.value;
if (product)
{
$.post( myUrl,
{ CodigoProduto : product }, // passing the product to my controller
function (retorno) {
// insert the partial view in a div
$('#AreaGenerica').html(retorno);
}
);
}
}
the first option returns a partial view that contains a javascript code
<script type=\"text/javascript\">
function PartialViewFunction () {
alert("test");
}
</script>
<h2>Option A</h2>
and the second option returns a partial view without any javascript code.
In my view i call the function inside the partial view
ViewFunction = function () {
// check if the function 'PartialViewFunction' exists.
if (typeof PartialViewFunction === "function")
{
PartialViewFunction();
}
};
My problem is that if i choose the first option and then the second the 'PartialViewFunction' is still being called but it shouldn't because it doesn't exists inside the second partial view.
I tried to remove the div containing my partial view following this answer but it didn't work.
Thanks in advance and i hope you can understand my english.
EDIT:
#(Html.Telerik().DropDownList()
.Name("grpAutorizacaoPublicacao")
.SelectedIndex(0)
.Effects(e => e.Opacity())
.ClientEvents(e =>
{
e.OnChange("onChange");
})
.DataBinding(db => db.Ajax().Select("_ListaGrupoAutorizacao", "Publicador")))
As a general rule I would avoid including JavaScript in partial views. You can search for advice about that. This might mean refactoring your JS to be generic and always included from the view proper. Such a design pattern would, I think, solve your problem, or at least make it easier to understand and fix.
Alternatively, it seems like you may need to limit onChange function to just the first select element. The code you have shown does not make it clear what calls the onChange event. You could include the html of the select element before and after the first selection is made.

SharePoint 2013 List - Tooltip over Items

We have large SharePoint lists with lots of columns. Our users are forgetting which cells they are viewing because after scrolling the headers disappear (no way to freeze headers like in Excel).
We want to try adding tooltips to the cell items so when they hover over it will display a tooltip with the column name.
Has anyone ever tried doing this before?
I have the following code which works initially on the load but stops working after the user sorts, filters or switches the list into Edit mode:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript">
jQuery(
function()
{
$('td').hover
(
function()
{
var idx = jQuery(this).parent().children().index(jQuery(this));
jQuery(this).attr('title',jQuery(this).parent().parent().parent().find('th').eq(idx).text());
jQuery('div.ms-core-brandingText').html(jQuery(this).parent().parent().parent().find('th').eq(idx).text());
}
)
}
);
</script>
Your code stops working because SharePoint reloads the list content. This is a common issue when adding client side scripts to SharePoint pages.
First, you should actually be able to render a view with frozen headers. Right, it doesn't come out of the box, but there are third party datatable tools available.
Another option is to include your code via the Client Side Rendering option. This is a broad topic, so probably the first step would be to google it.
Okay, getting closer, using CSR instead of just jQuery. This works but needs each field specified manually. Looking for a way to apply this to every field in the view.
<script type="text/javascript">
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
Templates: {
Fields: {
'Comments': {
'View': function (ctx) {
return String.format('<span title="{0}">{1}</span>', this.FieldTitle, ctx.CurrentItem.Comments);
}
},
'Name': {
'View': function (ctx) {
return String.format('<span title="{0}">{1}</span>', this.FieldTitle, ctx.CurrentItem.Name);
}
}
}
}
});
It occurs since when filtering/sorting is getting applied the List View is reloaded.
How to hover List Item in SharePoint 2013
The following function could be used for hovering List Item cells in SharePoint 2013:
function hoverListItems()
{
$('tr.ms-itmhover td').hover(
function() {
var $td = $(this);
var $th = $td.closest('table').find('th').eq($td.index());
$td.attr('title',$th.text());
}
);
}
Since in SharePoint 2013 Client-Side-Rendering (CSR) is the default rendering mode, the example below demonstrates how to register hoverListItem function using OnPostRender event
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
OnPostRender: function() {
hoverListItems();
}
});
Note: using the specified technique List Item hover will also work after
sorting/filtering is applied.
References
Introduction to Client-Side Rendering in SharePoint 2013
Tool-Tip Work-around:
The solution I have been using is a simple, non-html solution. I simply create a link to an item; insert it's own address (so that it doesn't go anywhere); then under the new LINK tab type the tip you want in the Description box.
save the page then try mousing over your new link, voilà
Hope that helps some!

Windows 8 Grid Template JS App, CSS manipulations dont show on all selected items in groupedItems view

I'm using the Win8 Grid View Template to display infos from a news site. In the lower menu bar i have implemented a function wich shuts off the titles, so that only the pictures are still visible.
This function is in a "global.js" file which is included in the "default.html" so it's available everywhere and it looks like this:
//function to turn titles off and on
function titleToggle() {
var titles = document.getElementsByClassName("item-overlay");
for (var i = 0; i < titles.length; i++) {
if (Global.titlesAreOn) {
titles[i].style.display = "none";
}
else {
titles[i].style.display = "";
}
}
Global.titlesAreOn = !Global.titlesAreOn;
};
So when i call this function from the menu bar it works for the first items, but when i scroll the end of the groupedItems view (hubview) the titles are still there. When i then scroll back to the beginning the titles are there again too.
I'm also calling the titleToggle function from the ready() function of the "groupedItems.js" to check whether or not to display the titles depending on a global variable. When i do that (whenever i come back to the hubpage) it works all the way, just as expected.
ui.Pages.define("/pages/groupedItems/groupedItems.html", {
navigateToGroup: function (key) {
nav.navigate("/pages/groupDetail/groupDetail.html", { groupKey: key });
},
ready: function (element, options) {
appbar.winControl.disabled = false;
appbar.winControl.hideCommands(["fontSizeBt"]);
appbar.winControl.showCommands(["titleToggle"]);
if (Global.titlesAreOn == false) {
Global.titlesAreOn = true;
Global.titleToggle();
}
I made a short video to show the problem, because its kinda hard to explain --> http://youtu.be/h4FpQf1fRBY I hope you get the idea?
Why does it work when i call it from the ready() function?
Does anyone have an idea? Is it some kind of automatic item caching in order to have better performance? And how could this be solved?
Greets and thanks!
First, here is why this might be happening - WinJS is using single page navigation for the app experience. This means that when you navigate to a new page, actually you don't. Instead the content is removed from the page and the new content is loaded in the same page. It is possible that at the moment you press the button not all elements have been loaded in the DOM and therefore they cannot be manipulated by your function. This is why when you call it from the ready() function it works - all contents are loaded in the DOM. It is generally better to do things in the ready() function.
About the behavior when you slide back left and the items are again reloaded with titles - for some reason the listView items are reloading. Maybe you are using live data from the news site and they are refreshing with the listView control's template again. I cannot know, but it doesn't matter. Hiding the elements is not the best approach I think. It is better to have two templates - one with a title element and one without. The button click handler should get the listView controls(they have to be loaded) and change their templates.
ready: function (element, options) {
var button = document.getElementById('btn');
button.addEventListener("click", btnClickHandler);
}
And the handler:
function btnClickHandler(e) {
var listView = document.getElementById("listView").winControl;
var template2 = document.getElementById("template2");
listView.itemTemplate = template2;
};

Categories