Using a custom javascript script file with durandal template - single-page-application

I work on a Visual Studio 2012 MVC4 Project with the Durandal template. In this template, the shell.js page gives us a quite simple menu solution where every elements are located on top. Personally I need something different. For that purpose, I have a javascript file named dropdown.js which allows me to show/hide sub menus. It works pretty well in a standard project but I was not able to do it working with the durandal template.
Here is what I try:
I added a reference to the dropdown.js script in the Index.chtml:
<script src="~/Scripts/dropdown.js"></script>
Then in the shell.html page, I would like to use it like this:
<li class="dropdown" data-role="dropdown">
...
...
</li>
Here is a little portion of the dropdown.js:
$(function () {
alert('XXXX');
$('[data-role="dropdown"]').each(function () {
alert('YYYY');
$(this).Dropdown();
})
})
As you can see, each element decorated with the 'dropdown' class should have been catched. It doesn't work with durandal. I placed some alert boxes to check it. The alert 'XX' is showed but the alert 'YY' is never showed.
I searched a bunch of hours without success.
Any idea?

Check out the life cycle events tha tyou can tap into for Durandal here
viewAttached may help since you can tap into when the view and dom are ready.

I think the problem is that when the dropdown.js function is executed before the menu renders and because of that the jquery selector doesn't catch any list item.
I think that your best option is to make a knockout binding to transform your list items in dropdowns.
The binding would look something like:
ko.bindingHandlers.dropdown= {
init: function (element, valueAccessor, allBindingsAccessor) {
$(element).Dropdown();
},
update: function (element, valueAccessor) {
}
};
And in the view:
<li class="dropdown" data-bind="dropdown : {}">
...
...
</li>

Related

Programmatically (not declaratively) render Meteor template

I'm trying to customize events added to FullCalendar, using eventRender. I'm aware that I can directly return HTML from my eventRender method, but I would prefer to programmatically merge event data with a predefined Meteor template (with associated events).
Previously I could have used Meteor.render() but that functionality is no longer available. I'm familiar with Template.dynamic, but that appear to only be available declaratively, and most of the questions I've seen here are quite old, so refer to deprecated functionality.
Here's what I would like to do:
Calendar - event population & rendering:
Template.dashboard.rendered = function(){
$('#calendar').fullCalendar({
events: function(start, end, timezone, callback) {
callback(Events.find().fetch());
},
eventRender: function(event, element) {
// PROGRAMMATICALLY RENDER TEMPLATE
// The following does not work - no data is attached
return Template.calendarEvent.renderFunction(event);
}
});
};
Event template HTML
<template name="calendarEvent">
{{title}}
<!-- full layout for rendering event here -->
</template>
Event template JS
Template.calendarEvent.events({
// define template event handlers
});
That function was not removed, it was renamed and quite a while ago it also changed behaviour (when spark was replaced by blaze).
What you are looking for is Blaze.renderWithData.
Note that it returns a Blaze.View and not a DOM object.
To make it a dom object you could provide it as a parent:
var renderedCalendarEvent = document.createElement("div");
Blaze.renderWithData(Template.calenderEvent, event, renderedCalendarEvent);
The DOM element renderedCalendarEvent will react to any reactive sources the template uses.
If you need HTML you can use Blaze.toHTMLWithData, but that html will remain static.
Blaze.toHTMLWithData(Template.calenderEvent, event);

ASP.Net Boilerplate & jTable

I have studied the ASP.Net boilderplate template (http://www.aspnetboilerplate.com/Templates) and made some custom changes.
I have a "GetComponentDataList()" method in my services. I played around with that and rendered it as a list like shown here:
<!-- Component list -->
<ul class="list-group" ng-repeat="component in vm.components">
<div class="list-group-item">
<br />
<span>Entry:</span>
<span>{{component.entry}}</span>
</div>
</ul>
components.js code:
vm.refreshComponents = function () {
abp.ui.setBusy( //Set whole page busy until getComponentDataList complete
null,
componentDataService.getComponentDataList( //Call application service method directly from javascript
).success(function (data) {
vm.components = data.componentData;
})
);
};
Now I would like to render the components via jTable. jTable expects an action to get the list of data:
listAction: '/api/services/app/componentData/GetComponentDataList',
How do I use jTable from boilerplate template?
1. Do I need to add a method in my "HomeController" to use jTable?
2. The result of my "GetComponentDataList" method in my service is of type IOutputDto.
That means the result of my service is not directly a list. There is one indirection
level inbetween. Seems like this does not fit together.
3. Can I provide a function in my JS-ViewModel and use that function instead of an action URL?
Any hint would be awesome.
Thx.
I'm working on a sample project to work ABP with jTable. I did not finish it yet. But you can check it. https://github.com/aspnetboilerplate/aspnetboilerplate-samples/tree/master/AbpWithjTable
Add abp.jtable.js to your file (https://github.com/aspnetboilerplate/aspnetboilerplate-samples/blob/master/AbpWithjTable/AbpjTable.Web/App/Main/libs/abp.jtable.js) after all ABP and jtable scripts.
See example js: https://github.com/aspnetboilerplate/aspnetboilerplate-samples/blob/master/AbpWithjTable/AbpjTable.Web/App/Main/views/people/people.js
See example C# App service: https://github.com/aspnetboilerplate/aspnetboilerplate-samples/blob/master/AbpWithjTable/AbpjTable.Application/People/PersonAppService.cs

how to attach events to generated html of a template in Meteor 0.8 with Blaze

I'm using Meteor 0.8 with Blaze and I want to attach events dynamically to HTML contents generated using UI.toHTML of a template. The functionality I am looking for is the alternative to Spark.attachEvents in Blaze.
What I have done so far is that I have created the following template to be used like a widget/component.
<template name="postLinks">
<div id="link-popover-wrapper" >
<ul class="link-popover">
{{#each linkOptions}}
<li><a tabindex="-1" class="link-action" id="link-{{value}}" href="#">{{label}}</a>
</li>
{{/each}}
</ul>
</div>
</template>
And the template is used in Helper of the myPostItem template.
Template.myPostItem.events({
'click .post-item-link-picker': function (evt, tmpl) {
var tempData = {linkOptions:[{label:'Favorite', value : 'favorite'}, ...]};
// Get the HTML content of the template passing data
var linkContent = UI.toHTML(Template['postLinks'].extend({data: function () { return tempData; }}));
// Attach events to the linkContent like in Spark
/*Spark.attachEvents({
'click link-action': function (e, tmpl) {
alert("Component item click");
}
}, linkContent);*/
// Popover the content using Bootstrap popover function
}
});
So my requirement is to attach events to a dynamically generated HTML contents.in the linkContent like Spark.attachEvents after the following line as mentioned in above code.
var linkContent = UI.toHTML(Template['postLinks'].extend({data: function () { return tempData; }}));
Hope somebody can help to find a way to do this in Meteor 0.8 with Blaze.
The reason that Spark-generated HTML could be directly inserted into the DOM is because it had "landmarks" - annotations that could be processed into events and handlers when the DOM nodes were materialized.
Blaze works differently - it inserts a UI component into the DOM directly and attaches events, using the UI.render function. It cannot directly attach template events to the DOM if you use UI.toHTML because there are none of the annotations that Spark had for doing this.
I'm also using Bootstrap popovers in my app, and as far as I know there's no clean way to insert reactive content into a popover. However, you can approximate it with a hack in the following way:
In the content callback of the popover, render the template with UI.toHTML - a nonreactive version of the content. This is necessary because otherwise the popover won't be sized and positioned properly.
Using a Meteor.defer call, replace the popover contents with reactive content, so they'll continue updating while the popover is open.
Because Bootstrap uses jQuery, you should be fine with removing reactive logic properly, for now. Future versions of Meteor will probably have easier ways to do this.

Angular JS: Detect when page content has rendered fully and is visible

My situation
I have a BIG list of people which all have their own profile pic and information. All items have some CSS3 styling/animations.
Im using:
<li ng-repeat="person in people">
Where people is an array with over 150 objects from an external JSON file that all have to show on the same page.
The page loads/renders slowly, and its not because of the $http GET function that gets the JSON data with people (which only takes about 100ms), but the rendering of the page and seemingly the rendering of all the css3 styling applied to each item (if i turn my CSS off it gets much faster).
My main problem
I can live with the page rendering slowly but what i really want is to detect whenever my heavy page has loaded its content in order to start and stop a loading indicator. Ive tried making a directive like this:
directive("peopleList", function () {
return function (scope, element, attrs) {
scope.$watch("people", function (value) {
var val = value || null;
console.log("Loading started");
if (val){
console.log("Loading finished");
}
});
};
});
And put this directive on the wrapper div that is loading my list of people. But the loading appears to stop whenever my object with JSON data has been filled, which only takes around 100ms, but the actual visual rendering of the page takes more like 4-5s.
Ive also tried solutions like http://jsfiddle.net/zdam/dBR2r/ but i get the same result there.
What i need
When i navigate through my pages (which all have the same kind of lists) i need something that tells me whenever the page has fully loaded and is visible for the user so that i know when to hide my loading indicator.
Try adding this directive -- the magic is in the link function:
directives
.directive('onFinishRender', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
scope.$evalAsync(attr.onFinishRender);
}
}
}
});
Add a loader as the first item:
<li ng-show="!isDoneLoading">
<div class="loading">Loading...</div>
</li>
Then in your li, add this:
<li ng-repeat="..." on-finish-render="isDoneLoading = true;"> ... </li>

Meteor, Form validation and Bootstrap accordion

I have a form in a Meteor application that contains a list of radio buttons that is made accessible by a Bootstrap accordion. I have implemented a validation routing in meteor that inserts classes into the input elements to mark them as valid/invalid.
Problem is: Everytime a validation state of one input element changes, the template is redrawn and the currently open accordion closes.
I solved this by doing this clumsy approach:
Meteor.startup(function() {
// track collapse state of accordion....
$('.collapse').on('shown', function() {
Session.set(addBookingCollapse, $(this).attr('id'));
});
});
Template.addrecord.helpers({
openAccordion: function(accordion) {
if (Session.get(addBookingCollapse) == accordion) {
return 'in'
};
}
});
<div id="collapseOne" class="accordion-body
collapse {{openAccordion 'collapseOne'}}">
...and so on for the other four collapsible elements
But for whoever's sake, there must be a more elegant solution? I do not want to waste a session variable for this....
It may help to put the input elements in {{#isolate}}{{\isolate}} blocks to avoid re-rendering the entire template. See: Meteor Isolates
I haven't really looked super close at your code/problem, but why do you use id's to target each of them on their own? Why not use a class for all of them like this:
$('.a-class-that-you-name').on('shown', function() {
var thisSpecificId = $(this).attr('id');
Session.set('addBookingCollapse', thisSpecificId);
});
Would that work?

Resources