Angular2: Dynamically create view selector based on model property? - javascript

I've been a C/C++ coder for a long time, but am new to Angular2 and TypeScript. I have a TypeScript class (call it Node) which has a type: string property that specifies what sort of node it is. (The data comes as JSON from a server, and is basically being parsed out as a syntax tree.)
What I'm doing now in the view template in order to choose the view for each Node object is using an ngSwitch to check the value of node.type, and then inserting the appropriate selector using ngSwitchCase for each possible case, e.g.:
<div [ngSwitch]="node.type">
<node-type-a-view *ngSwitchCase="'a'" [(node)]="node"></node-type-a-view>
<node-type-b-view *ngSwitchCase="'b'" [(node)]="node"></node-type-a-view>
<node-type-c-view *ngSwitchCase="'c'" [(node)]="node"></node-type-a-view>
<div class="debug" *ngSwitchDefault>
TODO: View for type "{{node.type}}" is missing
</div>
</div>
The problem is that there are over a hundred different node types, and so this is going to be very unwieldy, very quickly.
What I'd like to do is something like this (but obviously this doesn't work in Angular2):
<node-type-{{node.type}}-view [(node)]="node"></node-type-{{node.type}}-view>
Or, using an attribute selector:
<div node-type-{{node.type}}-view [(node)]="node"></div>
Is there any functionality that comes close to what I'm looking for? I don't need to dynamically create the node-type-*-view views themselves, just the template that references them.
Also, apologies if I'm getting this architecture completely wrong. I'm still wrapping my head around the way Angular2 does things!
Thanks for any assistance you can give!

Related

Dojo: defining Select-like widget with Options declaratively

The goal is to write custom widget similar to Select with options. Options should be able to be specified declarative. Example:
<div data-dojo-type="MySelect">
<span class="my-select-option" data-dojo-type="MySelectOption>Foo</span>
<span class="my-select-option" data-dojo-type="MySelectOption>Bar</span>
</div>
The problem is that all <span>s get overwritten and removed. What is the way to handle them correctly inside MySelect's JavaScript file?
You can use data-dojo-props together with dojo/parser to decoratively configure your custom widget.
Here a quick example for a possible markup, please note:
Use data-dojo-type to specify your custom "class" for your widget.
Use data-dojo-props to pass to the constructor any sort of configuration information upon instantiation.
data-dojo-props is a HTML5 data attributes and works with the latest version of Dojo.
Markup in your HTML:
<div id="instanceId" data-dojo-type="nameSpace/class" data-dojo-props="data: 'some data'"></div>
This reading is a good start:
https://dojotoolkit.org/documentation/tutorials/1.10/declarative/
For more information about parsing:
https://dojotoolkit.org/reference-guide/1.10/dojo/parser.html

Minimal jQuery template

I am creating a UI, in which user can add / delete items (of similar layout).
It starts with one item and you can click 'add' to add more. The UI consists of several different types of items.
What I am doing currently is populating a single item item 1 ( of each type ) and on add event, I clone the item 1, replace the changes done by user in item 1 and append the clone to the container.
In simple words, instead of dynamically creating html with jQuery, I am cloning html of a div. But in this approach , I had to change a lot of things to keep to give the new item to initial state.
So, I want to avoid the replacing the edits done by user, so I was thinking something like below,
<script type="text/template" id="item_type1">
<div>
<div>Box</div>
</div>
</script>
<script type="text/template" id="item_type2">
<div>
<div>Box2</div>
</div>
</script>
And on add event, I want to do something like $('#item_type1').html() and $('#item_type2') to create new items.
I know there are sophisticated libraries like handlebar and mustache and underscore has its own way of implementing templates.
But I am not using any of these already and thus do not want to included them just to copy content. I dont want anything special. I am not passing variables. I am just cloning some markup to use again and again.
Is this way to insert html in script tags , going to work in all browsers ? and is it a good way ?
EDIT:
Its for the wp plugin and I assume js is turned on , else the plugin wont work anyways.
What about:
Your HTML should be, for example:
<script type="text/template" id="item_type1">
<div>
<h1>Box1</h1>
<p>
</p>
</div>
</script>
And your code would be:
var templateHtml = $('#item_type1').html();
var $item = $(templateHtml);
$('body').append($item);
$item.on('click', function() {});
This is an easy way that will work on all browsers.
Step 1: Create an HTML file with your template inside of it
Step 2: Using jQuery's load() method, call your HTML template into a div element in the main HTML file:
$("#main-div").load("yourtemplate.html")
Step 3: Be amazed
Is this a good idea? It depends:
If it's a self contained application on a known environment with a determined supported browser and with equally determined settings (like if JavaScript is on or not) then yea, sure. Why not?
If it's open to the public in every single browser possible with many different configurations, then no, it's a horrible idea. If your user doesn't have JavaScript enabled, then your content doesn't show up. Also, if one of your scripts break in production, then you are again left with no content. You can learn this lesson from when Gawker made this same mistake

Need to pull additional data: how do I do that without making an AJAX call?

this should be a pretty straightforward question. My app is built on Ruby on Rails (I doubt that this is very important though -- I'm noting this so you all understand the syntax below)
I have these two div:
<div id = "1"><%= user.Name %></div>
<div id = "2">Placeholder</div>
When someone mouses over div with id 1, I would like to replace the content of the div with id 2.
The catch is that the content I want to replace div 2 with is contained in the user object. So ideally, I'd like to set some kind of additional tag on the div that I can lookup on the JavaScript mouseover. Otherwise, I'll have to do an AJAX call that will result in a DB query to pull the relevant data.
I have no idea what that tag would be ... any hints on what I could do?
Thanks!
Ringo
if possible, you can use the html5 'data-*' atribute to store whatever you want for further manipulation. learn more about this atribute | browser compatibility

Databinding a function in Angular.js

In angular I found out you can bind a template to a function which returns an array, like this:
<div class="cal_row" id ="id_{{task.id}}" ng-repeat="task in calendar.filtered()">
<div class="id">{{task.id}}</div>
<div class="task">{{task.task}}</div>
<div class="start">{{task.start}}</div>
<div class="finish">{{task.finish}}</div>
</div>
It's pretty cool, because that way I can, for example, avoid having to keep a variable around just to maintain the filtered version of the data.
However, I also loose the binding with the original data: when the underlying data changes, I can't seem to get angular.js to spot the change, and update the view.
Is there a way to do that? I tried to find anything in the docs, but couldn't
Thanks a lot
If you make a change to some data from outside angular, you have to use $myScope.$apply so angular knows something has changed. http://docs.angularjs.org/api/ng.$rootScope.Scope#$apply

Dojo Parameters for Tabs

I'm having trouble with the Dojo documentation (as usual).
On their TabContainer API, they list the second argument as an object called "params", but they never say what you can actually put in this params object. Can I specify the width? The height? Do I specify the id's of the divs I want to be the tabs inside the container?
There's also no specification of what attributes I would put in HTML if I wanted to specify the tab containers to be parsed by the Dojo parser. I found the following example that lets you put the title, selected and closable options. Is there anything else?
<div id="tabA1" dojoType="dijit.layout.ContentPane" title="First Tab" selected="true" closable="true">
First Tab
</div>
<div id="tabA2" dojoType="dijit.layout.ContentPane" title="Second Tab" closable="true">
Second Tab
</div>
<div id="tabA3" dojoType="dijit.layout.ContentPane" title="Third Tab" closable="true">
Third Tab
</div>
</div>
I am not an expert in Dojo widgets, but this is what I know:
All Dojo widget constructors have signature:
var widget = new Widget(params, node);
The best way to discover params is to look at the source code — don't get scared, they would be documented variables at the beginning of a relevant class.
The relevant file is usually simple to find using the name of the widget because they are named by their path.
The best way to look up this stuff is to use a Dojo checkout with your favorite text editor. But the nightly checkout works too (if you follow the trunk). Or the Trac source browser.
Don't underestimate the power of looking at tests and demos.
Example: dijit.layout.TabContainer ⇒ dijit/layout/TabContainer.js. If the file is missing look into directories of the hierarchy for _base.js, or some similarly sounding files — the latter can bundle related classes together. But in most cases (like with TabContainer) you'll find it immediately. Let's go and look.
There are two public documented parameters in the top of the class:
tabPosition — String. Defines where tabs go relative to tab content. "top", "bottom", "left-h", "right-h". Default: "top".
tabStrip — bool. Defines whether the tablist gets an extra class for layouting. Default: false.
_controllerWidget — just ignore it, no public parameters start with the underscore — it is a common JavaScript convention to designate protected members.
But it is not all. TabContainer is based on dijit.layout.StackContainer (just look at the dojo.declare() header). We can use StackContainer's public parameters as well:
doLayout — Boolean. If true, change the size of my currently displayed child to match my size. Default: true.
persist — Boolean. Remembers the selected child across sessions. Default: false.
As you can see the code and parametrs are nicely documented, yet not always reflected in the API tool. Now we can create the tab container with confidence.
But let's see it in action first. All Dijit tests are always in dijit/tests. Any dijit.layout.* widget will be tested in dijit/tests/layout. The relevant test file would be named something like test_TabContainer.html, and in fact I see 5 files for that:
test_TabContainer.html.
test_TabContainer_noLayout.html.
test_TabContainer_prog.html.
test_TabContainer_remote.html.
test_TabContainerTitlePane.html.
For example, let's recreate the first TabContainer of test_TabContainer.html:
var tc = new dijit.layout.TabContainer(
{persist: true, tabStrip: true}, "mainTabContainer");
Or we can do it like in the test inline:
<div id="mainTabContainer" dojoType="dijit.layout.TabContainer"
persist="true" tabStrip="true" style="width: 100%; height: 20em;">
...
</div>
Coming back to your original question: now you can see that width and height are specified simply as styles, no special attributes, nothing fancy, just some intuitive CSS. So if you want to do it programmatically, just set them on a node before creating a new instance of TabContainer.
Yeah, I wish the API doc got all these small details too, but the whole setup is intuitive, and relevant parts are documented right in the file. We did go to the source code, but we didn't try to decipher the source code, just read human-readable comments on the top of the class.

Categories

Resources