I'm using ui-router for navigation in an angular app. I use nested states/views in a hierarchy like this.
<!-- index.html -->
<h1>Page Title</h1>
<ui-view></ui-view>
<!-- Page1.template.html -->
<h1>Title 1</h1>
<ui-view></ui-view>
<!-- Page2.template.html -->
<h1>Title 2</h1>
<ui-view></ui-view>
<!-- Page3.template.html -->
<h1>Title 3</h1>
<ui-view></ui-view>
This result in as expected like this:
Is it possible to make the page look like this instead, i.e. render child views side by side:
Yes, it is possible. Take a look at the docs - Multiple Named Views. Basically you would have your page like:
<body>
<div ui-view="child1"></div>
<div ui-view="child2"></div>
<div ui-view="child3"></div>
</body>
and a state config
$stateProvider
.state('main',{
views: {
'child1': {
templateUrl: 'child1.html',
controller: 'Child1Ctrl'
},
'child1': {
templateUrl: 'child2.html',
controller: 'Child2Ctrl'
},
'child3': {
templateUrl: 'child3.html',
controller: 'Child3Ctrl'
}
}
});
Each child view can have it's own configuration, the same as original state configs.
Update:
If you want them to be dynamic i.e. specify views you want to render manually, going with this approach you could specify names in some $scope variable and ng-repeat over them:
.controller('SomeCtrl', function ($scope) {
$scope.views = ['child1', 'child3'];
})
HTML:
<div ng-repeat="view in views">
<div ui-view="{{view}}"></div>
</div>
See an example here: http://plnkr.co/edit/wVmR6q1UXqhNsF8afpd2?p=preview
Related
I am knew to AngularJS and trying to figure out a way to access controllers from other view pages.
For example, I have a _layout.cshtml page that contains global np-app and np-controller and in that global layout page there is a div that loads from different view that has anothernp-app & np-controller.
Please see below HTML and JS file:
Global layout html page:
<body ng-app="globalApp" ng-controller="globalCtrl">
<div ng-show="loader" class="progress-loader">
<h3>Processing...</h3>
<div class="progress">
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%">
<span class="sr-only">45% Complete</span>
</div>
</div>
<span class="text-danger">Please wait for the process to complete and do not refresh or close the browser.</span>
</div>
<div class="navbar navbar-inverse navbar-fixed-top" ng-app="navApp" ng-controller="navSearchCtrl">
<!-- NAV BAR code goes here -->
</div>
<div class="container body-content">
<!-- Other view gets loaded here -->
#RenderBody()
</div>
</body>
Search View HTML Page that gets loaded in #RenderBody in layout page
<div class="container" ng-app="searchApp" ng-controller="searchAppsCtrl">
<div id="search-form">
<form role="form" method="post" ng-submit="searchSubmit()">
<!-- Code goes here -->
</form>
</div>
</div>
AngularJS file:
angular.module('globalApp', ['searchApp', 'navApp'])
.controller("globalCtrl", function($scope, $rootScope) {
$rootScope.loader = false;
})
// Code goes here
});
var searchApp = angular.module("searchApp", []);
searchApp.controller('searchAppsCtrl', function($scope, $rootScope, request, $interval, $log) {
// Code goes here
});
var navApp = angular.module("navApp", []);
navApp.controller('navSearchCtrl', function($scope, $rootScope, request, $interval, $log) {
// Code goes here
});
My problem is that I cannot access angular bootstrap when it gets loaded in global layout page. I used angular inspector in chrome to see if I can see all the controllers. But I can only see two controllers, but not the third one that gets loaded from another view.
Please see below screenshot of Angular inspector in chrome.
I'm vague about I should be using in a sort of a simulation app where the user is presented with a web page that presents data from multiple domains and provides a variety of interactions that touch multiple domains.
In this case it is a real estate simulation where the UI presentation shows the user data about houses, offer to buy and sell, status of the users negotiations, etc, information about "state of the world" and that kind of thing. A fair amount of ajax going on in the page as well.
Can I just have a controller which is not associated with a particular domain and then just provide all the different objects? Maybe use a command object to deal with actions coming back from the user?
Hopefully this quesiton is not too vague for a coherent answer, I'm just looking for suggestions on the high level approach.
Yes, you can have a controller which does not directly correlate to a specific domain. For instance you could create a DashboardController. The use of command objects is up to you and your needs, but you can use Domain instance in the above controller just like any other controller.
As #Joshua Moore stated, it's no problem, let me give a small - shortened - example. (hope it gives you a bit of an idea...)
I use in the application a bootstrap-theme and the information on the dashboard (several statistic widgets) is generated through ajax-calls into the dashboard-controller.
First, the UrlMappings.groovy file:
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?(.$format)?"{
constraints {
// apply constraints here
}
}
"/"(controller: "dashboard", action:"index")
"500"(view:'/error')
}
}
Then the controller-code:
package example
import java.util.Random
import grails.converters.JSON
import groovy.time.TimeCategory
class DashboardController {
def index() {}
def contractAmountAsJson() { ...someCode; return Data as JSON... }
}
Then the index.gsp page:
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main">
<g:set var="entityName" value="${message(code: 'syParameter.label', default: 'SyParameter')}" />
<title><g:message code="default.list.label" args="[entityName]" /></title>
</head>
<body>
<!-- NEW WIDGET START -->
<article class="col-xs-12 col-sm-6 col-md-6 col-lg-6">
<!-- Widget ID (each widget will need unique ID)-->
<div class="jarviswidget" id="wid-id-8" data-widget-editbutton="false">
<header>
<span class="widget-icon"> <i class="fa fa-bar-chart-o"></i> </span>
<h2>Vertragsvolumen aktiver Kunden-Verträge pro Monat</h2>
</header>
<!-- widget div-->
<div>
<!-- widget edit box -->
<div class="jarviswidget-editbox">
<!-- This area used as dropdown edit box -->
</div>
<!-- end widget edit box -->
<!-- widget content -->
<div class="widget-body no-padding">
<div id="customerContractAmount" class="chart no-padding"></div>
</div>
<!-- end widget content -->
</div>
<!-- end widget div -->
</div>
<!-- end widget -->
</article>
</body>
</html>
And the javascript as an example:
if ($('#customerContractAmount').length) {
$.ajax({
url: '${request.contextPath}/dashboard/contractAmountAsJson?type=customer',
dataType: 'json',
success: function(chartData) {
Morris.${session?.user?.statisticStyle ? session.user.statisticStyle : "Area"}({
element : 'customerContractAmount',
data : chartData,
xkey : 'period',
ykeys : ['a', 'b', 'c'],
labels : ['bestätigt', 'erstellt', 'in Arbeit']
});
}
});
}
i'm new to Meteor and and i want to learn something about it. therefore i want to build a page were i can upload images via meteor-dropzone.
the upload is working with meteor-uploads.
now i want to get events, like 'addedfile' or 'drop' from the dropzone to fire some new functions.
HTML Page Profile2:
<template name="profile2">
<div class="ibox-content">
{{> dropzone url='http://localhost:3000/uploads' maxFilesize=5 addRemoveLinks=true acceptedFiles='image/*,jpg,jpeg,png' id='dropzoneDiv'}}
</div>
</template name="profile2">
In The JS File for Profile2 i wrote this:
Template.dropzone.events({
'addedfile #dropzoneDiv': function(e, template){
e.preventDefault();
console.log("Hello");
}
});
But i don't see something in the console.log output.
I'm sure i'm doing something wrong. But i have no i idea where the problem or the wrong understanding is.
Can somebody help me please.
Thanks.
Michael
after try and error. i found the solution. Maybe someone can explain it to me. because i don't understand it completely, why it's working now but so different to the normal Meteor event version.
Dropzone.options.dropzoneDiv = {
init: function() {
this.on("addedfile", function(file) { alert("Added file."); });
}
};
The Template like that:
<!-- Page heading -->
{{> pageHeading title='File upload' category='Forms' }}
<div class="wrapper wrapper-content animated fadeIn">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>Dropzone Area</h5>
{{>iboxTools}}
</div>
<div class="ibox-content">
<!-- For more info about dropzone plugin see this: https://github.com/devonbarrett/meteor-dropzone/ -->
{{> dropzone url='/uploads' id='dropzoneDiv'}}
</div>
</div>
</div>
</div>
</div>
</template>
Try the dropped event:
'dropped #dropzoneDiv' (e, template) => {
e.preventDefault();
console.log(e.originalEvent.dataTransfer.files); // this will contain the list of files that were dropped
}
I'm struggling with fullpage.js in Meteor.
When I add a button inside a template, the Template.templatename.events function does not fire on event.
For example:
Template HTML (messages.html)
<template name="messages">
<ul>
{{#each mess}}
<li>{{ messContent}}</li>
{{/each}}
<button class="addMessage">Add Message!</button>
</ul>
</template>
Template JavaScript (messages.js)
Template.messages.helpers({
mess: function(){
return Messages.find();
}
});
Template.messages.events({
'click .addMessage' : function(event){
console.log("clicked")
}
})
Main HTML
<head>
<title>fulltest</title>
</head>
<body>
{{> full}}
</body>
<template name="full">
<div id="fullpage">
<div class="section active">
<h1>First slide</h1>
{{> messages}}
</div>
<div class="section">
<h1>Second slide</h1>
</div>
</div>
</template>
My fullpage initialisation:
Template.full.rendered = function(){
$('#fullpage').fullpage();
}
If I remove the fullpage initialisation then the click event gets logged. Still new at Meteor, I didn't manage to grasp what's going wrong here.
All help much appreciated,
Joris
Use delegation or use verticalCentered:false and scrollOverflow:false.
From the fullPage.js FAQs:
My javascript/jQuery events don't work anymore when using fullPage.js
Short answer: if you are using options such as verticalCentered:true or overflowScroll:true in fullPage.js initialization, then you will have to treat your selectors as dynamic elements and use delegation. (by using things such as on from jQuery). Another option is to add your code in the afterRender callback of fullpage.js
Explanation: if you are using options such as verticalCentered:true or overflowScroll:true of fullPage.js, your content will be wrapped inside other elements changing its position in the DOM structure of the site. This way, your content would be consider as "dynamically added content" and most plugins need the content to be originally on the site to perform their tasks. Using the afterRender callback to initialize your plugins, fullPage.js makes sure to initialize them only when fullPage.js has stopped changing the DOM structure of the site.
Hello MarionetteJS Gurus,
I have what is probably a very simple problem, but I can't wrap my head around how to solve it. I have an application with 2 regions and 1 layout, and I'm utilizing the Ratchet CSS library for prototyping. Functionally, the goal is simple: display a list of contacts in one view, with a header and search bar. If the user selects a contact, remove the search bar and retain only the header.
The problem appears to be the wrapping divs that are required to swap views in and out. The Ratchet CSS needs the header bars to be directly above the content section in order to properly dock them at the top of the viewport, but Marionette's regions and layouts (at least with my configuration) are preventing this from happening. Perhaps I could better structure my views?
JSFiddle of the resulting output: http://jsfiddle.net/VB7py/3/ You'll notice that the header/search area overlaps the content area.
menuRegion contains a footer menu, and mainRegion contains a layout consisting of a header region, a search region, and a "main content" region. Below are some snippets of my code:
Regions
var App = new Marionette.Application();
App.addRegions({
headerRegion: "#header-region",
menuRegion: "#menu-region",
mainRegion: {
selector: "#main-region",
regionType: MainRegion
}
});
Layouts/Views
List.Layout = Marionette.Layout.extend({
template: "#contacts-layout",
regions: {
headerRegion: "#header-region",
searchRegion: "#secondary-header-region",
contactsRegion: "#contacts-region"
}
});
List.Search = Marionette.ItemView.extend({
tagName: "div",
template: "#contact-list-search",
className: "bar bar-standard bar-header-secondary"
});
List.Header = Marionette.ItemView.extend({
template: "#contact-list-header"
});
Templates
<!-- Application Layout -->
<script type="text/template" id="contacts-layout">
<div id="header-region" class="bar bar-standard"></div>
<div id="secondary-header-region">
</div>
<div id="contacts-region" class="content"></div>
</script>
<script type="text/template" id="contact-list-header">
<nav class="bar bar-standard"><h1 class="title">Contacts</h1></na>
</script>
<script type="text/template" id="contact-list-search">
<input type="search" placeholder="Search" />
</script>
<script type="text/template" id="menu-template">
<nav class="bar bar-tab bar-footer">
</nav>
</script>
The wrapping divs inside the regions did not seem to be a problem. However, you need to set those bar specific css classes to the regions instead of it's nested elements. Like:
<div id="header-region" class="bar bar-standard">
<div>
<nav>
<h1 class="title">All Contacts</h1>
</nav>
</div>
</div>
<div id="secondary-header-region" class="bar bar-header-secondary">
<div>
<input type="search" placeholder="Search">
</div>
</div>
See: http://jsfiddle.net/Cardiff/7Wd6W/
You could pre-set those classes on your region elements or add these specific classes on region initialization, see: https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.region.md#instantiate-your-own-region