I am trying to use ng-bind-html in a child component and it is not working. From what I read, You need to include ngSanitize. Which I have on am parent component and works fine there but can't get it to work on the child. Any ideas? Please let me know if you need more information. Thanks in advance!
var myApp = angular.module('subPackages', ['ngMaterial', 'ngMessages','ngSanitize']).config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
// Allow same origin resource loads.
'self',
// Allow loading from our assets domain. Notice the difference between * and **.
'<<Protected Content>>**'
]);
});
(function (app) {
'use strict';
app.component('appComponent', {
templateUrl: '../subpackages/templates/app-template.html',
controller: subAppController
});
app.component('cartSummary', {
templateUrl: '../subpackages/templates/cart-summary.template.html',
controller: cartSummaryController,
bindings: {
contentJson: '<',
cartPerfs: '<',
getGlobalContent: '&',
myNewHtml: '&',
callExecLocalProd: '&'
},
});
})(myApp);
Parent
function subAppController($sce, $compile) {
...
}
Child
function cartSummaryController($sce, $compile) {
this.$onInit = function () {
//Get content from Parent
this.globalContent = this.getGlobalContent;
this.cartSummary = this.cartPerfs;
this.myHtml = this.myNewHtml;
this.localProd = this.callExecLocalProd;
this.removePerf = function (obj) {
console.log("removing performance");
var liseqno = $("#mBtnRemove").data("liseqno");
var perfno = $("#mBtnRemove").data("perfno");
//Close modal
$('#myModal').modal('toggle');
var rpParam = [
{ elp_remove_li_seq_no: liseqno, elp_remove_perf_no: perfno }
]
this.localProd({ item: rpParam });
}
}; //End $onInit
this.confirmDelete = function (perf) {
console.log("Confirm Delete");
console.log(perf);
//Replace the perf_desc token with perf description
var msg = this.globalContent({ module: "subpackage", item: "modalMessage" });
var finalDesc = msg.replace(/{perf_desc}/g, perf.perf_desc);
//Set the body of the modal with our message
//$('.modal-body ').text($sce.trustAsHtml(finalDesc));
//$('.cs-modal-body').attr("ng-bind-html", $sce.trustAsHtml(finalDesc));
$('.cs-modal-body').attr("ng-bind-html", finalDesc);
//populate our data attributes that we will need later
$('#mBtnRemove').data("liseqno", perf.li_seq_no)
$('#mBtnRemove').data("perfno", perf.perf_no)
$('#myModal').modal();
}
}
In my html I am using
<p class="cs-modal-body" ng-bind-html="Here"></p>
if you use ng-bind-html="Here", then "Here" should be defined somewhere in your scope/context - it should be a string, which angular will try to parse as html
Define it in the controller.
Related
I am using angularjs version 1.6.4 with angular-multiple-select module for multi selecting. Every thing is working fine. I am able to select from suggestions but whenever i do selection "after-select-item" directive is not triggering. According to angular-multiple-select module documentation
afterSelectItem : Listen for event before adding an item
<div class="form-group float-label-control">
<label>Skills</label>
<multiple-autocomplete ng-model="model.user.skills"
object-property="name"
after-select-item="model.afterSelectItem"
suggestions-arr="model.skills">
</multiple-autocomplete>
</div>
My controller few code lines:
(function () {
"use strict";
var module = angular.module(__appName);
function fetchSkills($http) {
return $http.get(__apiRoot + "/skills")
.then(function (response) {
return response.data;
})
}
function controller($http) {
var model = this;
model.$onInit = function () {
fetchSkills($http).then(function (skills) {
model.skills = skills;
});
};
model.afterSelectItem = function (item) {
console.log("after select item");
console.log(item);
}
}
module.component("userEdit", {
templateUrl: "components/user-edit/user-edit.template.html",
bindings: {
userId: "<",
onUserSaved: "&"
},
controllerAs: "model",
controller: ["$http", controller]
});
}());
I need to load some template from path and concatenate with another one example:
(function (module) {
var modalDialog = function (modal) {
return function (item, template, header) {//template as parameter
var inlineTMp = "<div>inline template</div>";//this template
var concatTemplate = template + inlineTMp;//pseudo code
var modalInstance;
var options = {
template: concatTemplate,
controller: function () {
this.title = header || 'Dialog';
this.data = angular.copy(item);
this.noClicked = function() {
modalInstance.dismiss('cancel');
};
this.yesClicked = function (itemData) {
modalInstance.close(itemData);
};
},
controllerAs:"model"
};
modalInstance = modal.open(options);
return modalInstance.result;
}
}
module.factory("modalDialog", ['$modal', modalDialog]);
})(angular.module("common"));
so how do i download a template then concatenate with another and send to service.
Im' working on the Malhar Angular Dashboard, based on this github project https://github.com/DataTorrent/malhar-angular-dashboard.
As per the documentation in the link post just above, under the 'dataModelType' heading 1/2 way down:
`The best way to provide data to a widget is to specify a dataModelType in the Widget Definition Object (above). This function is used as a constructor whenever a new widget is instantiated on the page.`
And when setting up the Widget Definition Objects, there are various options to choose from :
templateUrl - URL of template to use for widget content
template - String template (ignored if templateUrl is present)
directive - HTML-injectable directive name (eg. "ng-show")
So when I add my own widget definition column chart, I attempt to use the 'template' option; however it does NOT inject the {{value}} scope variable I'm setting.
Using the original datamodel sample widget def, it works fine using the 'directive' option. If I mimic this method on my column chart definition then it works ! But it doesn't work using the template option.
Here's the 'widgetDefinitions' factory code :
(function () {
'use strict';
angular.module('rage')
.factory('widgetDefinitions', ['RandomDataModel','GadgetDataModel', widgetDefinitions])
function widgetDefinitions(RandomDataModel, GadgetDataModel) {
return [
{
name: 'datamodel',
directive: 'wt-scope-watch',
dataAttrName: 'value',
dataModelType: RandomDataModel // GOTTA FIGURE THIS OUT !! -BM:
},
{
name: 'column chart',
title: 'Column Chart',
template: '<div>Chart Gadget Here {{value}}</div>',
dataAttrName: 'value',
size: {width: '40%',height: '200px'},
dataModelType: ColumnChartDataModel
},
];
}
})();
and here are the factories:
'use strict';
angular.module('rage')
.factory('TreeGridDataModel', function (WidgetDataModel, gadgetInitService) {
function TreeGridDataModel() {
}
TreeGridDataModel.prototype = Object.create(WidgetDataModel.prototype);
TreeGridDataModel.prototype.constructor = WidgetDataModel;
angular.extend(TreeGridDataModel.prototype, {
init: function () {
var dataModelOptions = this.dataModelOptions;
this.limit = (dataModelOptions && dataModelOptions.limit) ? dataModelOptions.limit : 100;
this.treeGridActive = true;
//this.treeGridOptions = {};
this.updateScope('THIS IS A TreeGridDataModel...'); // see WidgetDataModel factory
},
updateLimit: function (limit) {
this.dataModelOptions = this.dataModelOptions ? this.dataModelOptions : {};
this.dataModelOptions.limit = limit;
this.limit = limit;
},
destroy: function () {
WidgetDataModel.prototype.destroy.call(this);
}
});
return TreeGridDataModel;
});
'use strict';
angular.module('rage')
.factory('ColumnChartDataModel', function (WidgetDataModel) {
function ColumnChartDataModel() {
}
ColumnChartDataModel.prototype = Object.create(WidgetDataModel.prototype);
ColumnChartDataModel.prototype.constructor = WidgetDataModel;
angular.extend(ColumnChartDataModel.prototype, {
init: function () {
var dataModelOptions = this.dataModelOptions;
this.limit = (dataModelOptions && dataModelOptions.limit) ? dataModelOptions.limit : 100;
this.treeGridActive = true;
var value = 'THIS IS A ColChartDataModel...';
//$scope.value = value;
this.updateScope(value); // see WidgetDataModel factory
},
updateLimit: function (limit) {
this.dataModelOptions = this.dataModelOptions ? this.dataModelOptions : {};
this.dataModelOptions.limit = limit;
this.limit = limit;
},
destroy: function () {
WidgetDataModel.prototype.destroy.call(this);
}
});
return ColumnChartDataModel;
});
and finally the directives:
'use strict';
angular.module('rage')
.directive('wtTime', function ($interval) {
return {
restrict: 'A',
scope: true,
replace: true,
template: '<div>Time<div class="alert alert-success">{{time}}</div></div>',
link: function (scope) {
function update() {
scope.time = new Date().toLocaleTimeString();
}
update();
var promise = $interval(update, 500);
scope.$on('$destroy', function () {
$interval.cancel(promise);
});
}
};
})
.directive('wtScopeWatch', function () {
return {
restrict: 'A',
replace: true,
template: '<div>Value<div class="alert alert-info">{{value}}</div></div>',
scope: {
value: '=value'
}
};
})
.directive('wtFluid', function () {
return {
restrict: 'A',
replace: true,
templateUrl: 'app/views/template2/fluid.html',
scope: true,
controller: function ($scope) {
$scope.$on('widgetResized', function (event, size) {
$scope.width = size.width || $scope.width;
$scope.height = size.height || $scope.height;
});
}
};
});
I'd like to know why ONLY the directive option will update the wigdet's data and not the template option.
thank you,
Bob
I believe I see the problem. The dataAttrName setting and updateScope method are actually doing something other than what you're expecting.
Look at the makeTemplateString function here. This is what ultimately builds your widget's template. You should notice that if you supply a template, the dataAttrName does not even get used.
Next, take a look at what updateScope does, and keep in mind that you can override this function in your own data model to do what you really want, a la:
angular.extend(TreeGridDataModel.prototype, {
init: function() {...},
destroy: function() {...},
updateScope: function(data) {
// I don't see this "main" object defined anywhere, I'm just going
// off your treegrid.html template, which has jqx-settings="main.treeGridOptions"
this.widgetScope.main = { treeGridOptions: data };
// Doing it without main, you could just do:
// this.widgetScope.treeGridOptions = data;
// And then update your treegrid.html file to be:
// <div id="treeGrid" jqx-tree-grid jqx-settings="treeGridOptions"></div>
}
});
Angularv1.1.5
Site: http://tilsa.azurewebsites.net
I have a very simple route setup however when the user goes from the default/home route to the detail (pregunta) route and then clicks the back button nothing happens. The 2nd/3rd time the back button is clicked the user returns (chrome) to the default/home route. I'm not sure as to how or why this is happening.
$routeProvider.
when('/', {
templateUrl: '/js/app/partial/index.html',
controller: 'IndexCtrl'
})
.when('/pregunta/:id', {
templateUrl: '/js/app/partial/detalle.html',
controller: 'PreguntaDetalleCtrl'
}).
otherwise({
redirectTo: '/'
});
Here are the two relevant controllers. I've removed some of the code that doesn't seem relevant (polling for new info/etc):
// load the index list of questions, the actual questions are loaded in parent scope
.controller('IndexCtrl', ['$scope', 'services', 'data', '$modal', 'navigation', 'timeFunctions', function ($scope, services, data, $modal, navigation, timeFunctions)
{
$scope.noEncodeUrl = 'http://tilsa.azurewebsites.net/';
$scope.url = encodeURIComponent($scope.noEncodeUrl);
// controls the back arrow visibility to go back
navigation.setReturn(false);
}])
.controller('PreguntaDetalleCtrl', ['$scope', '$routeParams', 'services', 'navigation', 'graphService', 'stringFx', '$timeout', 'timeFunctions', function ($scope, $routeParams, services, navigation, graphService, stringFx, $timeout, timeFunctions) {
$scope.notas = [];
$scope.comentario = '';
navigation.setReturn(true);
$scope.loadPregunta = function (id, loadComments)
{
services.preguntas.getDetalle(id).then(function (data)
{
$scope.safeApply(function ()
{
$scope.pregunta = data;
graphService.setProp('title', $scope.pregunta.pregunta);
$scope.noEncodeUrl = 'http://tilsa.azurewebsites.net/pregunta/' + id;
$scope.url = encodeURIComponent($scope.noEncodeUrl);
$scope.preguntaText = stringFx.removeAccent('¿'+$scope.pregunta.pregunta+'?');
});
if (loadComments)
{
$scope.commentTracker = {
defaults: { },
skip: 0,
take: 20
};
$scope.$on('$destroy', function (e)
{
$scope.stopPolling();
});
$scope.startPolling = function ()
{
// scrollTimeout will store the unique ID for the $setInterval instance
return $scope.scrollTimeout = timeFunctions.$setInterval(poll, 10000, $scope);
// Function called on interval with scope available
function poll($scope)
{
services.preguntas.getNotas($scope.pregunta.id, $scope.commentTracker, $scope.notas).then(function (data)
{
$scope.safeApply(function ()
{
for (i = 0, l = data.notas.length; i < l; i++)
{
$scope.notas.unshift(data.notas[i]);
}
});
});
}
}
$scope.stopPolling = function ()
{
return timeFunctions.$clearInterval($scope.scrollTimeout);
}
$scope.startPolling();
$scope.cargarAnteriores = function ()
{
//$scope.commentTracker.skip++;
services.preguntas.getNotas($scope.pregunta.id, $scope.commentTracker, $scope.notas, true).then(function (data)
{
$scope.safeApply(function ()
{
$scope.notas = $scope.notas.concat(data.notas);
$scope.masNotas = $scope.notas.length > 0;
});
});
}
$scope.cargarAnteriores();
}
});
}
$scope.notaNueva = function () {
//$scope.commentario;
if ($scope.comentario.length < 3)
{
alert('Escribe algo mas, no seas tacano con tus palabras');
return;
}
$scope.processing = true;
services.preguntas.insertNota($scope.pregunta.id, $scope.comentario, $scope.notas, false).then(function (data)
{
$scope.comentario = '';
$scope.processing = false;
$scope.loadPregunta($scope.pregunta.id, false);
services.preguntas.getNotas($scope.pregunta.id, $scope.commentTracker, $scope.notas).then(function (data)
{
$scope.safeApply(function ()
{
for (i = 0, l = data.notas.length; i < l; i++)
{
$scope.notas.unshift(data.notas[i]);
}
});
});
});
}
$scope.loadPregunta($routeParams.id, true)
$scope.$on('updatedpregunta', function (event, obj)
{
$scope.loadPregunta(obj, false)
});
}]);
I had this issue as well! Turned ut that artur grzesiak was right! I had a iframe on my page that had a binding for its src-attribute.
<iframe src="{{selected.url}}"></iframe>
Since the default value of $scope.selected.url was null the first thing that happened was that it was loading a url called null.
After some research I found that there was a special directive for the iframe:
<iframe ng-src="{{selected.url}}"></iframe>
This change solved my is
It seems that the Angular side of your app is fine.
99% the problem is caused by some external library. For sure there is some problem with this script kVEquaeit4R (it seens to be a facebook plugin), as it fails to load some resource (404 error): The resource you are looking for has been removed, had its name changed, or is temporarily unavailable. and as a consequence a couple of further errors are generated (look at the console). And in turn it prevents the app from calling window.location.hostname.replace what actually is present in the kVEquaeit4R script.
So my suggestion is as follow: remove this fb plugin from your site and check if the routing works properly...
I'm getting the error: NoMethodError: Method 'go_start' was not found on the controller
The function go_start is only in two places in my project (I searched):
StartRouter.js
define(['marionette'], function(Marionette) {
'use strict';
var StartRouter = {};
StartRouter.Router = Marionette.AppRouter.extend({
appRoutes: {
"start": "go_start"
}
});
return StartRouter;
});
And StartController.js
define(['underscore', 'marionette', 'app/vent',
'text!templates/StartLayout.html', 'views/InspectorStartView','views/InspectorStartView'],
function(_, Marionette, vent, layout, InspectorStartView, PlayerStartView) {
'use strict';
// public module API
var Controller = {};
// private
var Layout = Marionette.Layout.extend({
template: _.template(layout),
regions: {
inspector: "#inspector_choice",
player: "#player_choice"
}
});
// private
var _initializeLayout = function() {
console.log('initializeLayout...');
Controller.layout = new Layout();
Controller.layout.on("show", function() {
vent.trigger("layout:rendered");
});
vent.trigger('app:show', Controller.layout);
};
// controller attach a sub view/ search View
vent.on("layout:rendered", function() {
console.log('layout:rendered =>StartController');
// render views for the existing HTML in the template, and attach it to the layout (i.e. don't double render)
var inspectorStartView = new InspectorStartView();
Controller.layout.inspector.attachView(inspectorStartView);
var playerStartView = new PlayerStartView();
Controller.layout.player.attachView(playerStartView);
});
// controller show inspector in the layout / subview
vent.on('show:inspector', function(inspectorStartView) {
// console.log('show books event');
Controller.layout.inspector.show(inspectorStartView);
});
// controller show inspector in the layout / subview
vent.on('show:player', function(playerStartView) {
// console.log('show books event');
Controller.layout.inspector.show(playerStartView);
});
// public API
Controller.go_start = function(term) { **//<-- function go_start**
_initializeLayout();
//vent.trigger("search:term", term);
};
return Controller;
The really strange part is that Crome shows the error happening on line 77 of App.js which is:
app.addInitializer(function(options) {
// configure for loading templates stored externally...
Backbone.Marionette.TemplateCache.prototype.loadTemplate = function(templateId) {
// Marionette expects "templateId" to be the ID of a DOM element.
// But with RequireJS, templateId is actually the full text of the template.
var template = templateId;
// Make sure we have a template before trying to compile it
if (!template || template.length === 0) {
var msg = "Could not find template: '" + templateId + "'";
var err = new Error(msg);
err.name = "NoTemplateError";
throw err;
}
return template;
};
// Connect controllers to its router via options
// init router's router/controller
new options.router.Router({
controller: options.homeController
});
// init loginRouter's router/controller
new options.loginRouter.Router({
controller: options.loginController
});
// init helpRouter's router/controller
new options.helpRouter.Router({
controller: options.helpController //<-- Line 77
});
// init startRouter's router/controller
new options.startRouter.Router({
controller: options.startController
});
// init inspectorRouter's router/controller
new options.inspectorController.Router({
controller: options.inspectorController
});
// init playerRouter's router/controller
new options.playerRouter.Router({
controller: options.playerController
});
});
// export the app
return app;
});
The Help router and controller:
// HelpRouter.js
define(['marionette'], function(Marionette) {
'use strict';
var HelpRouter = {};
HelpRouter.Router = Marionette.AppRouter.extend({
appRoutes: {
"help": "go_help"
}
});
return HelpRouter;
});
<!-- routes/HelpController.js -->
define(['underscore', 'marionette', 'app/vent', 'text!templates/HelpLayout.html'],
function (_, Marionette, vent, layout) {
'use strict';
// public module API
var Controller = {};
// private
var Layout = Marionette.Layout.extend({
template: _.template(layout),
regions: {
faq: "#"
}
});
// private
var _initializeLayout = function () {
console.log('initializeLayout...');
Controller.layout = new Layout();
Controller.layout.on("show", function () {
vent.trigger("layout:rendered");
});
vent.trigger('app:show', Controller.layout);
};
// public API
Controller.go_help = function () {
_initializeLayout();
};
return Controller;
});
Anyone see what I'm doing wrong?
Here is something that I didn't think was supposed to happen:
// Includes Desktop Specific JavaScript files here (or inside of your Desktop router)
require(["app/App",
"routers/HomeController", "routers/StartController", "routers/LoginController",
"routers/InspectorController", "routers/PlayerController", "routers/HelpController",
"routers/DesktopRouter", "routers/LoginRouter", "routers/StartRouter",
"routers/InspectorController", "routers/PlayerController", "routers/HelpRouter" ],
function(App,
HomeController, StartController, LoginController, InspectorController, PlayerController, HelpController,
DesktopRouter, LoginRouter, HelpRouter, StartRouter, InspectorRouter, PlayerRouter) {
var options = {
homeController: HomeController,
startController: StartController,
loginController: LoginController,
helpController: HelpController,
inspectorController: InspectorController,
playerController: PlayerController,
router: DesktopRouter,
startRouter: StartRouter,
loginRouter: LoginRouter,
helpRouter: HelpRouter,
inspectorRouter: InspectorRouter,
playerRouter: PlayerRouter
};
App.start(options);
});
So I am requiring all my routers and controllers but when I run that code in the debugger I have some items that are undefined:
options: Object
helpController: Object
helpRouter: Object
homeController: Object
go_home: function () {
__proto__: Object
inspectorController: undefined
inspectorRouter: undefined
loginController: Object
loginRouter: Object
playerController: undefined
playerRouter: Object
router: Object
Router: function (){ parent.apply(this, arguments); }
__proto__: Object
startController: Object
go_start: function (term) {
__proto__: Object
startRouter: undefined
__proto__: Object
HomeController: Object
StartController: Object
StartRouter: undefined
DesktopRouter: Object
InspectorController: undefined
Why are some undefined? The StartRouter and StartController have the go_start function. The HelpRouter/Controller doesn't and shouldn't have go_start but it is throwing an error
All suggestions welcome.
Andrew
Looks like your RequireJS imports are out of order. The HelpRouter variable maps to the "routers/StartRouter" module, and all subsequent modules are off-by-one.
The AMD import format can easily lead to this types of simple errors that can take ages to debug, because that's somehow the place you never think to look. That's why I prefer the simplified CommonJS wrapper syntax provided by RequireJS:
define(function(require) {
var HomeController = require('routers/HomeController'),
StartController = require('routers/StartController'),
//etc...
});
For those of you just tuning in here is the working solution as proposed by fencliff.
// Includes Desktop Specific JavaScript files here (or inside of your Desktop router)
define(function(require) {
var App = require("app/App"),
// Routers with its controller
DesktopRouter = require("routers/DesktopRouter"),
HomeController = require("routers/HomeController"),
StartRouter = require("routers/StartRouter"),
StartController = require("routers/StartController"),
LoginRouter = require("routers/LoginRouter"),
LoginController = require("routers/LoginController"),
InspectorRouter = require("routers/InspectorRouter"),
InspectorController = require("routers/InspectorController"),
PlayerRouter = require("routers/PlayerRouter"),
PlayerController = require("routers/PlayerController"),
HelpRouter = require("routers/HelpRouter"),
HelpController = require("routers/HelpController");
var options = {
homeController: HomeController,
router: DesktopRouter,
startController: StartController,
startRouter: StartRouter,
loginController: LoginController,
loginRouter: LoginRouter,
inspectorController: InspectorController,
inspectorRouter: InspectorRouter,
playerController: PlayerController,
playerRouter: PlayerRouter,
helpController: HelpController,
helpRouter: HelpRouter
}
App.start(options);
return function() {};
});
I was a bit uncertain about returning an empty function but that is the only example I saw and it works. :-D