This may seem like an obscure question, but I am having issues with my angular inheriting scripts via an invoke script.
The generalization for this would be as follows:
We have a custom browser that will create a button when a custom "property" is added to an input object on our webpage(where the angular resides). When that property is added (similar to class and ID), it will put a button next to the Input object.
The issue I am having is that it will only work on objects outside of the ng-view.
The code works fine if the input object is located in my main index html file (before ng-view is called).
Is there a way to make it so that the custom scripts can be inherited in, what I believe, is the controllers?
Any tips are greatly appreciated.
EDIT: Here are some code snips that are currently being used to make this functionality possible.
The Browser Side:
string invokeScript = "(function(){function i(n,t){t.parentNode.insertBefore(n,t.nextSibling)}function r(n,t){var o={scannableInputId:n.id,scannerType:t},u=document.createElement(\"span\"),f=document.createAttribute(\"class\");f.value=\"input-group-btn\";u.setAttributeNode(f);var r=document.createElement(\"button\"),s=document.createTextNode(\"scan\"),e=document.createAttribute(\"class\");e.value=\"btn btn-primary\";r.appendChild(s);r.setAttributeNode(e);r.addEventListener(\"click\",function(){window.external.notify(JSON.stringify(o))});u.appendChild(r);i(u,n)}var n=document.querySelectorAll(\"[data-barcode-scan]\");for(var t in n)n.hasOwnProperty(t)&&r(n[t],n[t].getAttribute(\"data-barcode-scan\").toLowerCase())})();";
if (Web != null)
{
await Web.InvokeScriptAsync("eval",
new[]
{
invokeScript
});
}
The Website Side:
<h2>
Item (Demo): <input id="scannedValueDemoTextBox"
name="scannedValueDemoTextBox"
ng-model="scannedValueDemo"
type="text"
data-barcode-scan="single"
style="width: 200px"/>
The "data-barcode-scan="single" is what should trigger the button to appear, which works outside the ng-view/controllers.
Related
I have a template which is nested inside another template which I want to load when i click on a button.
So the nested template is loaded dynamically. This is what I have done so far.
This is the main body.html (this loads when a url is provided in the browser e.g. http://url#/newtemplate)
<div ui-view> </div>
Other section of the code has been removed for brevity
This is the new_template.html which I expects it to show when I click a button.
When I put a template name directly like below i.e. when I hard code it
<div ui-view="number1"></div>
It loads the template fully.
This is the dynamic model
<button ng-model="template_name" ng-value="number1">Button1</button>
<div ui-view="{{template_name}}"></div>
{{template_name}}
The above does not load the template as I expected. but it shows the string number1 when
the button is clicked
What can I do for it to load the template....
This is my controller
.state('parent',{
url: '/newtemplate',
views:{
'':{
templateUrl: "parent.tpl",
contoller:"controller",
},
'number1#parent':{
templateUrl:"number1.tpl",
contoller:"formcontroller"
},
'number2#parent':{
templateUrl:"number2.tpl",
contoller:"formcontroller"
},
'number3#parent':{
templateUrl:"number3.tpl",
contoller:"formcontroller"
}
}
})
Strange enough when I used the dot notation it did not work so I have to use the absolute naming method.
I also noticed that when I added the nested views as shown above the time it takes before the template gets loaded take a very long time.
Please I would appreciate any help which can allow me to load a nested view at runtime (possibly very fast)
Expecting more answer
I still hope that the I can make use of ui-view/ui-router because of the ability to make use of controller.
I'm not sure you can use uiView to load html dynamically.
I would try another possible solutions:
Use directives
Using ngInclude
I'll leave you an example with ngInclude: https://next.plnkr.co/edit/M5hl71mXdAGth2TE?open=lib%2Fscript.js&deferRun=1&preview
TL;TR; is below
I'm dealing with a huge application where everything is made super-generic to easily expend. One of the components is the dialog. Now before your answer is, use ngInclude or angular templates, let me explain how these work and why we would like to stick to them.
The flow of creating this dialog:
From somewhere in javascript a javascript function is called.
That constructs the container for the dialog. Position, widths, heights, gray background, etc.
Once that is present, a loading indicator will show up, while a GET request takes place to the back-end.
At the back-end Action, a view name is provided and a model.
This view (a .cshtml file) gets loaded into a string builder. To give you an idea of what happens, here is a piece of code where the view gets loaded.
var sb = new StringBuilder(1);
using (StringWriter sw = new StringWriter(sb))
{
.....
var helper = new HtmlHelper(viewContext, viewDataContainer);
using (helper.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
helper.RenderPartial(viewName, model);
}
return sb.ToString();
}
Then the string is returned, in javascript it is eventually set as html: diag.html(jsonResponse.data);
Now the view that I load, contains angular elements, like ng-controller and brackets to show something from that controller. Here is the .cshtml:
#model int
<div ng-controller="dialogGridColumnSelectionController as dgc" ng-init="dgc.init(#Model)">
<table>
<thead>
...
<tbody>
<tr ng-repeat="col in dgc.tableColumns">
<td>
<input type="checkbox" name="some" ng-value="dgc.hide"/>
</td>
<td>{{col.headerName}}</td>
<td>{{col.Description}}</td>
</tr>
</tbody>
</table>
</div>
A few statements:
ng-app was tried later, it should not be needed here because the <body> element already has this.
The dialog is within the <body> element.
No errors, no angular warnings.
{{col.headerName}} shows exactly as how it is shown, so angular is not working.
The controller and all the other required javascript files are already loaded on the page from where this dialog is opened. Also tried to add them here, no difference. I also tried to load angular there again, that does give me a warning that I tried to load it more than once. So the scripts are there.
Now I kind of doubted that this would work from the beginning, but I just want to make sure before we start a major rework of the dialogs.
So my question is, is it possible? Can a view that is initiated from .html() (in javascript) have angular? How do I "start" Angular? Or why is it not working with generated html?
TL;TR and EDIT:
After some digging, I eventually did this:
dialog.html(jsonResponse.data);//dialog is a created jquery element, jsonResponse.data contains the `.cshtml` content
if (options.angularCompile && options.angularScope) {//I've set them in options
options.angularCompile(dialog)(options.angularScope);//= $compile(dialog)($scope) or $compile(dialog.contents())($scope)
}
From the html above, it does fire the init function. That function correctly loads data (from other injected factories).
var self = this;
this.tablePageID = 0;
this.tableColumns = [];
$scope.hello = "hii";
this.init = function (tablePageID) {
self.tablePageID = tablePageID;
self.tableColumns = gridTableFactory.getTableColumns(tablePageID);
}
But once completed and the dialog is shown, it still has no angular working.
Worth noting is that the ng-repeat has done it job at the beginning, there are no items. Looks like it compiles and forgets.
Try executing $scope.$apply(); after using the $compile. You may need to inform angular to update its bindings. Also try to avoid using jQuery directly and use angular.element("#....") instead.
__What I am trying todo____
Right now I am working with custom HTML5 tags. I am trying to create a tab-control element that is easy to set up. Todo this I create a parent element called 'tab-set' which works much like the 'ul' tag.
To insert tabs, you simply insert 'tab-element' tags (like 'li' tags). The tags can implement own behavior through custom prototypes which extend standardized element-prototypes such as the basic HTMLElement and are then registered with 'document.registerElement()'. At that point there are also opportunities to set callbacks that let you know whenever your element has been created or attached to something, which is what I use to do the necessary calculations on the placement of the individual tabs on the tab-control.
Let me say up-front that I've had trouble with this at first, then got it working, but upon rewriting the whole thing had troubles again for who knows why.
So, in the creation routine of the tab-set I iterate through all the child-tab-elements, calling their custom function 'setDimension', or atleast I am trying to. For some reason Chrome won't initialize the tab-element prototype (setDimension etc) before it has called both 'createdCallback' and 'attachedCallback' on my tab-set. This means that I can't call the child elements custom functions to set it's placement on creation of the tab-set.
Here you have some code samples of what I just described.
simple.html
...
<tab-set>
<tab-element>
<img>guybrush</img>
</tab-element>
<tab-element>
<img>le chuck</img>
</tab-element>
</tab-set>
...
tabs.js
...
tabSet = Object.create(HTMLDivElement.prototype);
tabSet.attachedCallback = function(){
for(/** calculations here **/)
listOfChildren[index].setDimensions(/** placement info **/);
//
// Chrome console: 'setDimensions' is not a function!
//
}
tabElement = Object.create(HTMLDivElement.prototype);
tabElement.setDimensions = function(/** placement info **/){
$(this).css(...);
}
document.registerElement('tab-set',tabSet);
document.registerElement('tab-element',tabElement);
...
The weird thing is that I have a working version of this, and yes, I have tried to emulate it's particular conditions such as for example loading the html-portion through jquery's .load() routine. But no matter what I do, I can not get this to work in my current script. What knowledge am I missing?
Thanks in advance for any help.
__ Solved __
All I had todo was add a link-tag inside the tab-set and have the tab-elements load it's containing style-class. I guess making the tab-elements have a css-class is somehow provoking Chrome to load their prototypes 'prematurely'.
I am new to DOJO. I have a custom widget , which uses a template file for the dialog box contents.
I am extending dijit.Dialog in the script file.
dojo.declare(
"custom.credentials",
[dijit._WidgetBase, dijit._Templated,dijit._WidgetsInTemplateMixin,**dijit.Dialog**],
{
templatePath: dojo.moduleUrl("custom", "templates/credentials.html"),
....
....
postCreate: function() {
this.inherited(arguments);
alert(this.containerNode);
alert(this.mainDIV);
},
});
My Template test file looks like this
<div data-dojo-attach-point="mainDIV">
Login Dialog Box template here
</div>
For some reason, when I alert on this.mainDIV, I get 'undefined'. It does not read the template file. Also, this.containerNode gives me 'HTMLDIVElement', (parent dijit dialog DIV).
I am not able to figure out after a lot of trial error where exactly the issue is. Any help would be greatly appreciated.
Calling code
function opnPop(){
var pop= dijit.byId("customPopup");
pop.show();
}
<div dojoType="custom.credentials" id="customPopup"/>
Note : *When dijit.Dialog is not extended* it reads the template file without any problem, I.e, I am able to access this.mainDIV.innerHTML , that contains my own inner html contents.
Thank you.
If Dialog has to be sub-classed, then it must be the base class. Here, it seems that it is used as a mixin. Anyways, the problem is with the template that is used.
The template will be parsed and used by the code in Dialog. So, the template mentioned here has nothing but a div element with an attach point. There is no "containerNode" element (ie. attach point) and you are trying to access it in your js code, which will give error.
More important, the "titleBar" & "titleNode" elements are also missing form template, which will give errors while parsing the template. In order to avoid that, the code part that uses these elements need to be removed from js, to avoid error. So the widget creation will be successful. Try with the standard dijit.Dialog's template.
Add the data-dojo-attach-point="mainDIV" to the top level Dialog's div in the template.
In template, more things can be added, which won't cause any issues. But, if removed anything, will cause problem. If we are sub-classing a class/widget, we need to comply to the existing code.
Maybe I've picked a totally inappropriate/bad example.
What I have is a user control that contains a bunch of dynamically created Telerik RadGrids.
My user control is added to a couple of Telerik RadPageViews that are part of a RadMultiPage that is used alongside a RadTabStrip.
What I need to do is call a Javascript function in my usercontrol to update it's display whenever it's parent RadPageView is selected.
So basically I have the following Javascript code:
function OnClientTabSelected(sender, args)
{
// Get the MyControl that is on this tab
var myControl = $find("whatever");
// Call a method that updates the display
myControl.doSomething();
}
Thanks,
David
You can add a wrapper div in your User Control and then extend that div using jQuery to add your desired methods and properties. The trick is to set the div's id='<%=this.ID%>' - that way the div has the same ID as the User Control (which is fine because the User Control doesn't actually render anything - only its contents).
Then back on your containing page, you can just reference your UserControl's ID using $get('whatever') - and you'll actually select your extended div.. which will have all your methods and properties on it.
The nice thing about this approach is that all of your methods and properties and neatly scoped and nothing is in the global namespace.
I have a full demo solution and details here if you want more info:
http://programmerramblings.blogspot.com/2011/07/clientside-api-for-aspnet-user-controls.html
Just make a call to javascript method in input button if you are sure about the name of that function.
<input type="button" value="test" onclick="doSomething()" />
If you place any javascript code in the control that will be spit on the page and it will be available for calling provided both of them are in the same form.
for example your code will look like this if you look into the source of that page.
<script type="text/javascript">
function doSomething()
{
alert(new Date());
}
</script>
<div>
<span id="MyControl1_Label1">Dummy label</span>
</div>
<hr />
<input type="button" value="test" onclick="doSomething()" />
Edit: This is not a good way to access these methods in my opinion. When you are putting some javascript code inside a control then it should be used in that control only (There is no rule as such, its just a design suggestion). If you are trying to access javascript code of a control from outside that control then you need to revisit your design.
If you can give us more details on why you want to access that method, may be we can suggest some better way to do that.
Update: (As you have modified your question): Bit tricky to answer this as I dont have hands on experience with Rad controls. I guess there should be some feature which will help you to update the controls in that page without using javascript, may be have a look at clientside-API provided for Rad.
May be somebody who knows about RAD controls will help you.
You should make the control method public
public void doSomething
and call this from the page
myControl1.doSomething();