angular onclick events on plain text html elements - javascript

New to angular, I have array of responses with below structure
{
type:typeid,
title:"99695 procedure id",
description :"procedure 99265 related to repair of system 56 with combination of 98745 procedure"
}
I need to identify numbers with specific pattern and make them clickable elements[not hyperlinks, better understanding purpose I made hyperlinks here], description field from API response should be formatted like below.
procedure 99265 related to repair of system 56 with combination of 98745 procedure
Using regex I had replaced matching patterns in text with <span style='cursor:pointer'><a>matchednumber</a></span> so subsequently when angular component rendering 'description' field all numbers are getting highlighted as clickable elements.
Problem
I need to register/trigger events like mouse over or click events. How can I bind events on above elements. I tried life cycle methods
ngAfterViewInit on component, ngAfterContentInit on directive
but they need some 'template' to be defined first to get element reference to bind events(correct me if I'm wrong here)
Going through lot of articles/examples but not able to get solve. Can you please suggest how can dynamically register events on 'plan html' content rendering from angular component.

Related

Trigger Dynamic Actions from a JavaScript Animation in Oracle APEX

Hello fellow developers.
I am working with Oracle APEX. I have found a pretty beautiful JavaScript library about animation and I would like to use it in order to make my application more beautiful and to show the user the path in order to make some configurations in the database.
The library that I have found is called JIT (https://philogb.github.io/jit/demos.html) and I would like to use this instance: https://philogb.github.io/jit/static/v20/Jit/Examples/Spacetree/example1.html.
After I implement the animation in APEX I would like to add some dynamic actions. For example every time one node is being clicked, a different region underneath the animation is being displayed and the other sub-regions are being hid.
Until now I have uploaded the JIT library and the JavaScript code that contains the Events and the functions about the animated tree in the shared components of my application. Also I have managed to display the animation in the Oracle APEX page, through an HTML code. I caught the Event that is happening whenever one node is being clicked. I have created also one dynamic action on a Region, and with this dynamic action I would like to show this Region. And every time, one different node is being clicked this Region is getting hidden. The dynamic action I have created has the existing attributes:
*Event ='Change'
*Selection Type = JQuery Selector
*JQuery Selector = $("#P5_NAME").val('INAS006E ');
,where P5_NAME is a field that I store in the JavaScript code the name of the node that is being clicked and 'INAS006E' is the name of one specific node.
*Action = Show
*Selection Type = Region
*Region = Test JS
, the name of the region that I want to display.
The biggest problem that I don't know how to overcome is, to pass the variable in the JavaScript code, node.name, in the Oracle APEX in order to trigger the dynamic actions.
Here is the Event that is being triggered where one node is clicked and where I store the node.name.
onBeforeCompute: function(node){
Log.write("loading " + node.name);
alert(node.name);
$("#P5_NAME").val(node.name);
},
In conclusion, I want after one node is being clicked, one region is getting showed after I click one the next node, the previous node is being hid and another one is coming up. But in order to do that, I have to pass the variable from JavaScript code into Oracle APEX.
I have managed to solve this problem after a lot of testing and searching.
The truth is that the answer is simpler than I expected. All I had to do, is to change a little bit the code of the function, that is being triggered. The correct function is:
onBeforeCompute: function(node){
Log.write("loading " + node.name);
alert(node.name);
$s("P5_NAME",node.name);
},
The $s("P5_NAME",node.name) sets the value of textfield P5_NAME with the name of the node.

How can I manipulate HTML elements which are added during the runtime?

The code im working on first makes a call to the database. Through this call, it is determined wether there are available workstations in the office or not.
If there are available workstations, "option" elements are added to a "select" element. This is achieved via jquery:
$('#idofselectelement').html(data)
Where "data" represents the markup to be inserted into the "select" element.
Now, my problem is that I'm trying to implement some code which checks wether your "favorite workstation" is available in the selected timeframe and then automatically preselects the respective workstation from the dropdownmenu in the "select" element. Everything is working so far, except for the selection of the workstation from the dropdown menu :/
The part of
I'm rather new to programming with javascript and the HTML DOM, so I'm not sure whether the fact that the options im trying to chose from are added during the runtime?
The code I've tried to manipulate the dropdown menu with is like this:
$('#idofselectelement').val(favoriteworkstation);
However, as I said, this doesn't work.
I've also already tried to output (console.log) the select element's length property right after the code which adds the markup with the available options has run.
But according to the output Im getting, the length is zero Oo
However, the dropdownmenu is definitely being created AND I can indeed manipulate it, but unfortunately not in the way I want to.
If I add an onclick event which sets the value of the respective select element, then the value in the select field indeed changes to the value specified in the event handler.
So I wonder why I can't have the favorite workstation preselected after the timeframe was chosen...
EDIT:
For further insight into the problem, I'm adding a bit more code here.
This is what the HTML Select element looks like BEFORE anything is added during the runtime:
<label for="#sitz">Sitz Nr.</label>
<select type="text" class="form-control" id="sitz" name="sitz" value="">
the markup which is added during the runtime
<option>workstationvalue</option>
<option>workstationvalue</option>
//and so on, depending on the situation...
This is a timing issue.
The js trying to find the element is faster than the actual add of the element to DOM.
Can you describe what you want to do? You might be able to do that before adding the element to DOM.
Editing before adding to DOM is possible if you convert your String to an jQuery object
var $jqueryObject = $(data);
$jqueryObject.find('.classYouSearch').val(value);
$('.whereToAd').html($jqueryObject);

How can I share javascript/html among several elements on a page?

I have web page with two textboxes on it. Upon clicking on the first, I have a bootstrap modal that displays with a searchable treeview. You click an item in the treeview, the modal closes, and the selection appears in the textbox. Works perfectly!
Now I have decided that for the other textbox I want to do the same thing. The only difference is the modal has a different title, and the source data for the modal treeview comes from a different endpoint. All the other javascript to support searching and highlighting within a treeview, opening and closing a modal, etc, is the same.
To get it to work, I duplicated all html for the modals and the js code and just changed the ID's to avoid clashes between the two. I cannot live with myself for doing this!
So in the end, I have some js and html that work together as a component that I want to reuse on a page among several textboxes or whatever type of widget I may create. How can I design my app so I can share this code and not duplicate it all over the page?
I think webcomponents is the way to go. You could create a component that receives the id and other needed data as parameters and then create instances of it...
There is a lot to unpack in this question. High level, to achieve what you're asking with JS…
You could:
Build a method that accepts an event object (or jQuery event object) as its argument; and handles extracting extracting data from the attributes of that element, setting the title, AJAXing the treeview, and returning the selection/setting the text box value
embed the unique data in data-attributes on each text box
set the click event listener to pass the event.target element, with its unique data- attributes to the method
Markup:
<input type="text" id="foo" data-endpoint="/path/to/endpoint_1" data-title="Modal Foo" value="" />
JS
function on_click_modal_spawning_textbox( event ) {
// get the salient data from the `data-` attributes on the `event.target`
// do modal stuff, programmatically replace the modal title, AJAX treeview, et cetera…
}
// assuming you're using jQuery, otherwise this would be a vanilla `.addEventListener()`
$( document ).on( 'click', 'input[ data-endpoint ]', on_click_modal_spawning_textbox );

Table in AngularJS app with many "select" elements built with ng-repeat takes very long

I have a table with variable number of records (could be up to hundreds) where its body is build with one ng-repeat.
Within each record, there are two input fields of type select where their contents is also built using ng-repear and the number of options for each is about 100.
This is working right now, except that it takes a lot of time for the page to be built (several seconds; I guess due to the large number of html records that AngularJS is adding to the DOM).
Here is an example of one of the selects:
<select class="form-control" ng-model="One_Source.Measuring_Method_Code">
<option ng-selected="{{One_Method.Value == One_Source.Measuring_Method_Code}}"
ng-repeat="One_Method in All_Collections.Parameters_Test_Methods"
value="{{One_Method.Value}}"
title="{{One_Method.Test_Method_Name}} | {{One_Method.Method_Internal_Name}}">
{{One_Method.Value}}
</option>
</select>
Two questions:
Is there a simple way to speed up the page building process?
As shown in the example, each option in the list has a title clause displaying a detailed description of the option's meaning. How can I add a title to the select showing the description of the current value?
For the first question I was thinking about building the list of options for each select element only upon clicking on it, but I'm not sure if that would be the best way to do it.
Try using one time bindings so that Angular doesn't watch the value by prefixing it with ::. It can also be more efficient to use track by in your ng-repeat if each row has a unique value, like an ID.
<option
ng-selected="{{One_Method.Value == One_Source.Measuring_Method_Code}}"
ng-repeat="One_Method in All_Collections.Parameters_Test_Methods track by One_Method.id"
value="{{::One_Method.Value}}"
title="{{::One_Method.Test_Method_Name}} | {{::One_Method.Method_Internal_Name}}"
>
{{::One_Method.Value}}
</option>
If you still can't gain the performance you're expecting from #doublesharps's answer, you will have to implement one of the following:
You could build a custom list that has a 'load more' button which would destroy say the first '50' options and load the next 50.
A better option would be to turn this into an autocomplete, where the user searches for values.
Virtual repeat - Something angular material does really well, it constantly draw's and re-draws new elements based on the scroll position inside the element.
Other resources:
http://blog.scalyr.com/2013/10/angularjs-1200ms-to-35ms/
https://github.com/stackfull/angular-virtual-scroll
http://klajd.github.io/angular-virtual-repeat/#/Home
I found a PARTIAL SOLUTION that still needs to be polished but is quite promising.
During creation of the page, I do not make use of ng-repeat for the options but instead deploy a single option with the value received for the field from the database (if any, otherwise the select element is left blank).
When the user clicks on the select element a $scope function is invoked that checks the number of options within the select element and, if less or equal to 1, the inner HTML of this select element is re-generated and deployed.
Though clicking on all these select in the page will take (accumulative) a comparable time as when built upon load, this time is distributed over several events (the user clicking on all the select elements) and hence it is not perceived by the user.
Now, by polishing I mean that there is a strange behavior. In order to see the generated list of options, I need to click on the select twice. Will keep investigating this and post the solution (hoping I find one).

JSF custom component losing input focus on ajax update

I'm writing an autocomplete custom component as a learning exercise with JSF
2.1.3. The idea (which is probably pretty familiar) is to enter some text into
and input component and present a list box with matching values. The idea is
to have a keyup javascript event on the input which calls jsf.ajax.request()
to update the component. So far I've got a component which I can include like
this:
<mycc:autocomplete id="myauto" searchMethod="#{bean.doSearch}"/>
This renders html like this:
<span id="myauto">
<input type="text" id="myauto_input" name="myauto_input"
onkeyup="com.myco.ajaxRequest(this, event)"/>
<select id="myauto_listbox" name="myauto_listbox">
<option value="1st">First</option>
<option value="2nd">Second</option>
</select>
</span>
The com.myco.ajaxRequest() javascript function (keyup) does this:
jsf.ajax.request(comp, null, {
execute: 'myauto',
render: 'myauto'
});
So because I want to rebuild and rerender the listbox with the suggestions
list, I'm re-rendering the custom component 'myauto'. By specifying execute:
'myauto' the decode() method executes and I can get the input value. By
specifying render: 'myauto' the encode...() methods execute to regenerate
the html.
This is all fine but because I'm rendering the parent of the myauto_input
component I lose input focus every time the keyup event fires.
If I specify something like render: 'myauto_listbox' (I only really want to
rerender the listbox after all) the problem is that the encode...() methods
don't execute, because they're for the custom component as a whole, not just
the listbox. And it would be in one of the encode...() methods that I rebuild
the listbox containing the suggestions.
The component extends UIInput and I generate markup in a separate renderer
(componentFamily = "javax.faces.Input") in the encodeEnd() method (so this
always runs after any supplied converter - not yet implemented). I suppose
that forcing focus from javascript is a horrible hack and to be avoided.
I'm a bit unsure where to go with this, but I suspect that what I'm seeing
indicates that I'm approaching this in the wrong way somehow. If anyone
would be good enough to point me in the right direction I'd greatly appreciate
it.
I've spent some time looking into this and the general issue of losing focus after
an ajax update is fairly common and is described in Jim Driscoll's blog (see
'Keeping Focus').
In the case of my custom component I (think I...) have to update the custom component
itself which is the parent of the input, so I'm going to lose focus as a result of the
ajax update, and that's just the way it is. As such I've looked at what needs to be
done to restore focus, and it seems that in my renderer encode I simply have to
forcibly restore focus to the input, but only when responding to the POST sent from the onkeyup event by jsf.ajax.request. I use jQuery and just calling .focus() isn't
enough because you also have to get the cursor position to the end of any existing
input. This code below seems to work ok:
<script>
jQuery(function($){var cid='#myauto_input';$(cid).focus().focus().click();$(cid).val($(cid).val());});
</script>
(note: .focus().focus().click() required for IE8, just .focus() works on chrome...)
So it looks like the horrible hack has saved the day. I did wonder if there would be
any difference if I used the jQuery ajax routines rather than the jsf ajax library but
I don't suppose it would make any difference.

Categories

Resources