I have a ng-repeat in my view and I want to pass the object from my ng-repeat to a javascript function but when I try to display it on the console it gives me undefined.
Here is my html:
<!-- Panel -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-primary">
<div class="panel-heading">
{{card}}
</div>
<!-- /.panel-heading -->
<div class="panel-body">
<div id="nvd3-container" class="md-card" style="overflow-x: auto" ng-if="dataloaded0">
<md-card-content id="nvd3-scrollable-content" style="width: {{width}}px; height: 350px;">
<md-tabs md-dynamic-height="" md-border-bottom="">
<md-tab ng-repeat="pu in selectedKpi" label="{{pu.dprdProuNr}}">
<md-content class="md-padding">
<div class="row">
<div class="col-md-6">
{{pu.item1}}
{{pu.item2}}
</div>
</div>
</md-content>
</md-tab>
</md-tabs>
</md-card-content>
</div>
</div>
<!-- /.panel-body -->
<a href="" ng-click="footerLinkClicked(pu)">
<div class="panel-footer">
<span class="pull-left">Trend</span>
<span
class="pull-right">
<i class="fa fa-arrow-circle-right"></i>
</span>
<div class="clearfix"></div>
</div>
</a>
</div>
</div>
</div>
<!-- /.panel -->
Here is my js file that returns undefined:
angular.module('App')
.directive('KpiParameter', function() {
return {
restrict: 'E',
templateUrl: 'app/kpi/kpi-parameter/kpi-parameter.html',
scope: {
card: '=',
kpiParamCallback: '&',
selectedProductionUnit: '<'
},
controller: function($scope, $rootScope, KpiChartFactory, $filter) {
console.log("!???????");
console.log($scope.selectedProductionUnit);
$scope.$watch('selectedProductionUnit', function() {
console.log($scope.selectedProductionUnit);
console.log("Changed");
KpiParamUpdated();
$scope.kpiParamCallback({
selectedProductionUnit: $scope.productionUnitDefault
});
}, true);
function KpiParamUpdated() {
console.log("KPiParamUpdated");
console.log($scope.selectedProductionUnit);
$scope.dataloaded0 = true;
KpiChartFactory.get({ pu: $scope.selectedProductionUnit }, function(data) {
$scope.selectedKpi = data;
console.log($scope.selectedKpi);
$rootScope.$broadcast('kpiParams', $scope.selectedKpi);
});
}
$scope.footerLinkClicked = function(pu) {
console.log("parameters received :");
console.log(pu);
}
},
controllerAs: "KpiPCtrl"
};
});
Do you have any idea why? I need to define it also in my js file?
As found in the docs of AngularMaterial, you can only achieve what you want to do by using md-on-select
Attributes
Parameter Type Description
label string
Optional attribute to specify a simple string as the tab label
ng-disabled boolean If present and expression evaluates to truthy, disabled tab selection.
md-on-deselect expression Expression to be evaluated after the tab has been de-selected.
md-on-select expression Expression to be evaluated after the tab has been selected.
md-active boolean When true, sets the active tab. Note: There can only be one active tab at a time.
Note: This event differs slightly from ng-click, in that if a tab is already selected and then clicked, the event will not fire.
Your call to footerLinkClicked() has no way of knowing which pu to use unless you tell it which one to use. And since it's outside of your ng-repeat, there's no overly easy way to do that.
md-tabs has an attribute called md-selected that allows you to store the currently selected index in a variable. So assuming that selectedKpi is an array (or is array-like), you can do this:
<md-tabs md-dynamic-height="" md-border-bottom="" md-selected="selectedTab">
and this:
<a href="" ng-click="footerLinkClicked(selectedKpi[selectedTab])">
and you should be all set.
Related
I have a vue select component, according to selection I want to change content, and show the loading screen on change event.
<template>
<div>
<div class="row component-separation audit-select">
<div class="col-md-4 pull-right">
<v-select
id="auditModeSelect"
:options="auditOptions"
label="label"
placeholder="Change Audit View Type"
class="form-control border-bottom"
v-model="auditOption"
#input="changeViewMode"
:clearable="false">
</v-select>
</div>
</div>
{{loadingTheContent}}
<div v-if="loadingTheContent">
<loading/>
</div>
<div v-else>
....
</div>
</div>
</template>
changeViewMode(selectedMode) {
this.loadingTheContent = true;
if (selectedMode && selectedMode.value === 1) {
...
} else {
...
}
this.loadingTheContent = false;
},
But loadingTheContent variable value is always false, not changing.
I also tried with adding custom button to trigger but same thing exists
I have an input that I'm using in relation two an unordered list with two list items, which is in place, but I"m trying to figure out how I can change the input name/id with the click of one of the list items.
The items are not links or buttons, so I just want to be able to click the item text and if 'Public' is clicked, the input name would become public, if 'Internal' is clicked I would want the input name to be internal
I'm using Vue which may have some better options, but basically I just want to send the name of the input later on in an ajax call and I only want the name to be determined by the click of a list item potentially with a default.
What is the best way to achieve this with Vue being used?
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li>Public</li>
<li>Internal</li>
</ul>
</div>
<div>
<input type="text" name="public">
</div>
</div>
</div>
First step: use component data to your advantage
You can simply store the desired input name attribute in the component data, e.g. inputName. Then, use v-on to bind a click event listener to your elements, so that whenever they are clicked, you invoke a method that updates the inputData property of your component.
new Vue({
el: '#app',
data: {
inputName: '',
},
methods: {
setInputName(str) {
this.inputName = str;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li v-on:click="setInputName('public')">Public</li>
<li v-on:click="setInputName('internal')">Internal</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>
Better: Use v-for to generate list items dynamically
If you don't want the manually provide the argument to the method, there's an easier way: you simply create a list of allowed names in the component data, too, and use v-for to generate the list dynamically:
new Vue({
el: '#app',
data: {
inputName: '',
allowedNames: ['Public', 'Internal']
},
methods: {
setInputName(str) {
this.inputName = str.toLowerCase();
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li
v-for="(allowedName, i) in allowedNames"
v-bind:key="i"
v-on:click="setInputName(allowedName)">
{{ allowedName }}
</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>
Even better: if there is no one-to-one correspondance between list item text and the desired name attribute
This can be useful in the case when, for example, you want the text to read Public but the name attribute to be another value. Instead of an array of strings, you can use an array of objects:
new Vue({
el: '#app',
data: {
inputName: '',
allowedNames: [{
label: 'Public (or any other arbitrary text you like)',
name: 'public'
}, {
label: 'Internal (or any other arbitrary text you like)',
name: 'internal',
}]
},
methods: {
setInputName(str) {
this.inputName = str;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li
v-for="(allowedName, i) in allowedNames"
v-bind:key="i"
v-on:click="setInputName(allowedName.name)">
{{ allowedName.label }}
</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>
I'm having trouble getting ng-show to work inside my directive template. I'm using AngularJS 1.6.4. The Chrome debugger shows the successful change from ng-show="true" to ng-show="false" in the final DOM. But the element stays hidden when set to true. It appears this is because AngularJS adds a ng-hide class to the list in the element, but does not remove this when ng-show changes to true. Maybe AngularJS does not evaluate at this stage? How do I get this to show/hide properly?
I've been playing around with this for a while and have tried may different approaches including using the loading parameter directly instead of using the scoped showspinner. I've also tried omitting the mustaches (AngularJS expression) in the directive template like so: ng-show="showspinner" but this makes it worse by just rendering to ng-show="showspinner" instead of ng-show="false".
Following is my code.
The $ctrl.result is loaded asynchronously while the $ctrl.resultsLoading is set to true, when the results are done loading it's set to false:
<report-tile
title="My Report Item"
value="{{$ctrl.result.count|number:0}}"
loading="{{$ctrl.resultsLoading}}">
</report-tile>
This is my ReportTileDirective.js
(function(angular) {
"use strict";
angular
.module("app")
.directive(
"reportTile",
["$templateCache", "$compile" ,function($templateCache, $compile) {
return {
restrict: "EA",
scope: {
title: "#",
value: "#",
loading: "#"
},
link: function (scope, element, attribues) {
scope.showspinner = false;
scope.$watch("loading",
function () {
scope.showspinner = attribues.loading;
console.log("watching::loading::" + attribues.loading);
});
},
templateUrl: "app/directives/ReportTileDirective.html"
};
}]);
}(window.angular));
This is my ReportTileDirective.html
<div class="col-sm-4 col-md-3 col-lg-2 col-padding">
<div class="panel panel-default">
<div class="panel-heading tile-title">
<strong>{{title === '' ? 'Loading' : title}}</strong>
</div>
<div class="panel-body" style="text-align: right">
<strong>
<i ng-show="{{showspinner}}" class="fa fa-refresh fa-spin"></i>
{{value === '' ? 0 : value}}
</strong>
</div>
</div>
Finally this is the rendered DOM (as shown in the Chrome debugger Elements tab) when loading is done and it switches to true, the ng-hide is not removed:
<i ng-show="true" class="fa fa-refresh fa-spin ng-hide"></i>
Please help! Thank you!
I found my question is a duplicate of this one and thanks to #CodeWarrior's answer I was able to fix this. I can remove the whole link: section and use the loading parameter directly if: I bind it with = instead of # and then get rid of the expression syntax, so that this is evaluated in the directive rather than beforehand.
So my directive usage changes to:
<report-tile
title="My Report Item"
value="{{$ctrl.result.count|number:0}}"
loading="$ctrl.resultsLoading"> <!-- notice no mustaches here -->
</report-tile>
and my directive JavaScript file changes to:
(function(angular) {
"use strict";
angular
.module("app")
.directive(
"reportTile",
["$templateCache", "$compile" ,function($templateCache, $compile) {
return {
restrict: "EA",
scope: {
title: "#",
value: "#",
loading: "=" /* notice the = binding */
},
templateUrl: "app/directives/ReportTileDirective.html"
};
}]);
}(window.angular));
Then finally my directive template changes to:
<div class="col-sm-4 col-md-3 col-lg-2 col-padding">
<div class="panel panel-default">
<div class="panel-heading tile-title">
<strong>{{title === '' ? 'Loading' : title}}</strong>
</div>
<div class="panel-body" style="text-align: right">
<strong>
<i ng-show="loading" class="fa fa-refresh fa-spin"></i> <!-- notice to mustaches here -->
{{value === '' ? 0 : value}}
</strong>
</div>
</div>
I want to use an Angular directive to wrap a Bootstrap panel. I'm running into a problem, though, if I want to use HTML tags within the body of the panel.
Given:
$scope.panel = {
title: "Title",
body: "This is some <strong>cool</strong> text!"
};
I would want my panel to render with a body that looks like:
This is some cool text!
But instead it's rendering as:
This is some <strong>cool</strong> text!
Is it possible to achieve the effect I'm looking for?
Edit:
Directive
aModule.directive('myPanel', function() {
return {
restrict: 'E',
scope: { panel: '=' },
templateUrl: './tmp/my-panel.html'
};
});
Template:
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">{{panel.title}}</h3>
</div>
<div class="panel-body">
<p>{{panel.body}}</p>
</div>
</div>
In use:
<my-panel panel="panel"></my-panel>
Using the answer below:
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">{{panel.title}}</h3>
</div>
<div class="panel-body">
<p ng-bind-html="panel.body"></p>
</div>
</div>
To bind HTML to an Angular variable, you have to use the $sce module's trustAsHtml function to verify the content.
$scope.panel = {
title: "Title",
body: $sce.trustAsHtml("This is some <strong>cool</strong> text!");
};
You also need to use ng-bind-html:
<p ng-bind-html="panel['body']"></p>
You no longer need the {{ panel.body }} since the ng-bind-html directive will evaluate the expression and insert the resulting HTML into the desired element in a secure way.
I have a pure css3 modal call by a link, and I wish to pass some variable to the modal.
Modal
<div id="reasonmodal">
<div class="modal-content">
<div class="header">
Reason
</div>
<div class="copy">
//content
</div>
<div class="footer">Close</div>
<br />
</div>
HTML
//some other code with foreach appid
Click
I want pass foreach appid to the modal, any suggestion to do that ? Thanks
i have an idea (js only):
<a href="#reasonmodal" class="modal-link" rel="<?=$app_id?>" >Click</a>
Close
and modal action :
$(".modal-link").click(function(){
$("#submit-link").attr('href','?r=Register/UpdateReason&appid='+$(this).attr('rel'));
$($(this).attr('href')).modal('show');
});
Just print the var
<div id="reasonmodal">
<div class="modal-content">
<div class="header">
Reason
</div>
<div class="copy">
//content
</div>
<div class="footer">Close</div>
<br />
</div>
I see that you want to dynamically pass variables to the model each time click the html div.
Just use ajax post to get these values and update the modal content before it is triggered
Modal
<div id="reasonmodal">
<div class="modal-content">
<div class="header">
Reason
</div>
<div class="copy" id="modal_content">
//content
</div>
<div class="footer">Close</div>
<br />
</div>
Add a onclick event to html div
<a href="#reasonmodal" onlick='updateModal()'>Click</a>
Implement the updateModal() function which will POST an ajax request to get data. Something like this:
function viewDetail()
{
$.ajax({
type: "POST",
url: <?php echo "\"" . Yii::app()->createUrl('controller/action') . "\""; ?>,
data: { param : "value"},
}).done(function(msg){
//update the model content with msg responded from server
document.getElementById("modal_content").innerHTML = msg;
});
}
The modal will be triggered after the html content is updated.
(Give me a vote-up if it works for you)