By following this link Alfresco custom control in stencil i have made custom multi select control with the same steps as mention in the post (Alfresco Activiti) , multi select works fine but problem i am facing rite now in visibility operation is not working of the control for example there is a text field and in its visibility section i am applying condition whenever value of multi select control value is middle and high hide this control as mentioned in the attached image. . code for multi select custom control is
<div ng-controller="multiselectController">
<select name="multiselect" multiple ng-model="field.value"
ng-options="option.code as option.name for option in field.options"
class="form-control ng-pristine ng-valid ng-scope ng-valid-required ng-touched"
>
<option value="">--Select State--</option>
</select>
</div>
angular controller code is
angular
.module('activitiApp')
.controller('multiselectController',
['$rootScope', '$scope', '$http',
function ($rootScope, $scope, $http) {
// that responds with JSON
$scope.field.options = [];
// in case of array values without rest services
if($scope.field.params.customProperties.ElxwfOptionsArrayMultiselect){
$scope.field.options = JSON.parse($scope.field.params.customProperties.ElxwfOptionsArrayMultiselect);
} else($scope.field.params.customProperties.ElxwfRestURLforMultiselect) {
$http.get($scope.field.params.customProperties.ElxwfRestURLforMultiselect).
success(function(data, status, headers, config) {
var tempResponseArray = data.RestResponse.result;
for (var i = 0; i < tempResponseArray.length; i++) {
var state = { name: tempResponseArray[i].name };
$scope.data.states.push(state);
}
}).
error(function(data, status, headers, config) {
alert('Error: '+ status);
tempResponseArray = [];
}
);
}
}]
);
help me in this regard.
Likely this is because your visibility code is not expecting an array.
You need to test for array contains rather than equal and not equal.
Related
Within my view I have a select box. If a certain value is selected I want more form options to appear below using #if.
#model App.ViewModels.JobVM
<div class="row">
<div class="form-group">
#Html.Label("Job Type", new { #class = "control-label" })
#Html.DropDownListFor(model => model.JobId,
new SelectList(App.ViewModels.JobVM.GetJobs(),
"Value", "Text"),
"--Choose Job Type--",
new { #class = "form-control"})
</div>
</div>
...
#if (Model.JobId == 1)
{
.... more form options
}
However when running if the select option that give Job ID 1; the form options don't render.
Is there a reason why the form options do not appear when the Select option changes? Or will I have to use javascript to accomplish this goal?
It's expected behavior as view is rendered on server once before sending data to browser. However, for displaying additional inputs you can use both methods - js or partial views (even with ajax if you need) you have to use only JavaScript to show/hide other elements of form for required cases.
The #if statement and Model.JobId executed server-side, hence Model.JobId value doesn't change when the dropdown selected value has changed because change event occurred in client-side. By handling change event with JS, you can use AJAX call to set the value and display additional form options which contained inside partial view:
jQuery AJAX call
$('#JobId').change(function () {
var jobId = $(this).val();
if (jobId == 1) {
$.ajax({
type: 'GET', // or 'POST'
url: '#Url.Action("ActionName", "ControllerName")',
data: { JobId : jobId },
success: function (result) {
$('#formoptions').html(result);
},
// other stuff
});
}
else {
$('#formoptions').empty();
}
});
Controller Action
public ActionResult ActionName(int JobId)
{
// do something
return PartialView("_FormOptions", viewmodel);
}
If the form options are already rendered together inside view, instead of using server-side #if block, simply use a <div> placeholder and toggle its visibility like this:
$('#JobId').change(function () {
var jobId = $(this).val();
if (jobId == 1) {
$('#formoptions').show(); // show form options
} else {
$('#formoptions').hide(); // hide form options
}
});
HTML
<div id="formoptions">
<!-- more form options -->
</div>
I'm using Meteor with React. I have a really simple goal, but i have tried a lot and can't solve it for myself. I will show you my attemps below.
I want to create a form for the Ingredients. At the first moment there is only one input (for only one ingredient) and 2 buttons: Add Ingredient and Submit.
class IngredientForm extends Component {
render() {
return(
<form onSubmit={this.handleSubmit.bind(this)}>
<input type="text"/>
{ this.renderOtherInputs() }
<input type="button" value="Add Ingredient" onClick={this.addIngredient.bind(this)}>
<input type="submit" value="Submit Form">
</form>
);
}
}
So when I click Submit then all the data goes to the collection. When I click Add Ingredient then the another text input appears (in the place where renderOtherInputs() ).
I know, that Meteor is reactive - so no need to render something directly. I should underlie on the reactive data storage.
And I know from the tutorials the only one way to render something - I should have an array (that was based on collection, which is always reactive) and then render something for each element of that array.
So I should have an array with number of elements = number of additional inputs. that is local, so I can't use Collection, let's use Reactive Var instead of it.
numOfIngredients = new ReactiveVar([]);
And when I click Add button - the new element should be pushed to this array:
addIngredient(e) {
e.preventDefault();
let newNumOfIngredients = numOfIngredients.get();
newNumOfIngredients.push('lalal');
numOfIngredients.set(newNumOfIngredients);
}
And after all I should render additional inputs (on the assumption of how many elements I have in the array):
renderOtherInputs() {
return numOfIngredients.get().map((elem) => {
return(
<input type="text"/>
);
}
}
The idea is: when I click Add button then new element is pushed to the ReactiveVar (newNumOfIngredients). In the html code I call this.renderOtherInputs(), which return html for the as many inputs as elements I have in my ReactiveVar (newNumOfIngredients). newNumOfIngredients is a reactive storage of data - so when I push element to it, all things that depends on it should re-render. I have no idea why that is not working and how to do this.
Thank you for your help.
Finally I got the solution. But why you guys don't help newbie in web? It is really simple question for experienced developers. I read that meteor and especially react have powerful communities, but...
the answer is: we should use state!
first let's define our state object in the constructor of react component:
constructor(props) {
super(props);
this.state = {
inputs: [],
}
}
then we need a function to render inputs underlying our state.inputs:
renderOtherInputs() {
return this.state.inputs.map( (each, index) => {
return (
<input key={ index } type="text" />
);
});
}
and to add an input:
addInput(e) {
e.preventDefault();
var temp = this.state.inputs;
temp.push('no matter');
this.setState({
inputs: temp,
});
}
p.s. and to delete each input:
deleteIngredient(e) {
e.preventDefault();
let index = e.target.getAttribute('id');
let temp = this.state.inputs;
delete temp[index];
this.setState({
inputs: temp,
});
}
In my autoform the value of a field is the difference of two other input fields. It is not allowed to be updated by the user. Unfortuantly at the moment it is not possible to set a single field to readonly in a form. So my approach is to create an autoValue and a custom Validation to prevent an update
My code so far:
'SiteA.Settings.RXSignalODU1difference': {
type: Number,
label: "RX Signal [dBm] ODU1 difference (without ATPC +/- 3dbm)",
decimal: true,
autoform: {
type: "number"
},
autoValue: function() {
var ODU1gemessen = this.field("SiteA.Settings.RXSignalODU1");
var ODU1planned = this.field("SiteA.Settings.RXSignalODU1planned");
if (ODU1gemessen.isSet || ODU1planned.isSet) {
return ODU1gemessen.value - ODU1planned.value;
}
},
custom: function() {
var ODU1gemessen = this.field("SiteA.Settings.RXSignalODU1");
var ODU1planned = this.field("SiteA.Settings.RXSignalODU1planned");
var dif = ODU1gemessen.value - ODU1planned.value;
if (this.value !== dif) {
return "noUpdateAllowed";
}
}
},
My Simple.Schema message:
SimpleSchema.messages({noUpdateAllowed: "Can't be updated"});
Unfortunatly no message pops up.
EDIT
This method will create a disabled input box within your form that will automatically show the difference between two other input fields as the user types.
First, we define session variables for the values used in the calculation and initialize them to undefined.
Template.xyz.onRendered({
Session.set("ODU1gemessen", undefined);
Session.set("ODU1planned", undefined);
});
Then we define two events, that will automatically update these session variables as the user types.
Template.xyz.events({
'keyup #RXSignalODU1' : function (event) {
var value = $(event.target).val();
Session.set("ODU1gemessen", value);
},
'keyup #RXSignalODU1planned' : function (event) {
var value = $(event.target).val();
Session.set("ODU1planned", value);
}
});
Then we define a helper to calculate the difference.
Template.xyz.helpers({
RXSignalODU1difference : function () {
var ODU1gemessen = Session.get("ODU1gemessen");
var ODU1planned = Session.get("ODU1planned");
if (!!ODU1gemessen || !!ODU1planned) {
return ODU1gemessen - ODU1planned;
}
}
});
My HTML markup looks like this. Note, to still control the order of the form, I use a {{#autoform}} with a series of {{> afQuickfields }} rather than using {{> quickForm}}.
To display the calculated difference, I just create a custom div with a disabled text box.
<template name="xyz">
{{#autoForm collection="yourCollection" id="yourId" type="insert"}}
<fieldset>
<legend>Enter legend text</legend>
{{> afQuickField name="SiteA.Settings.RXSignalODU1" id="RXSignalODU1"}}
{{> afQuickField name="SiteA.Settings.RXSignalODU1planned" id="RXSignalODU1planned"}}
<div class="form-group">
<label class="control-label">RXSignalODU1difference</label>
<input class="form-control" type="text" name="RXSignalODU1difference" disabled value="{{RXSignalODU1difference}}">
<span class="help-block"></span>
</div>
</fieldset>
<button class="btn btn-primary" type="submit">Insert</button>
{{/autoForm}}
</template>
Original Answer - not recommended
If you are generating your form as a quickForm, you could do something like
{{>quickForm collection='yourCollection' omitFields='SiteA.Settings.RXSignalODU1difference'}}
This will leave this field off the form, so the user won't be able to update it.
If you still want to display the value somewhere along with the form as the user types in the other two values, you could define a helper in your client side js
something like
Template.yourFormPage.helpers({
diff: function () {
var ODU1gemessen = $('[name=SiteA.Settings.RXSignalODU1]').val();
var ODU1planned = $('[name=SiteA.Settings.RXSignalODU1planned]').val();
if (!!ODU1gemessen || !!ODU1planned) {
return ODU1gemessen - ODU1planned;
}
}
});
You'll want to double check how the field names are being rendered in your DOM. Autoform assigns the name attribute using the field names in your schema, but I don't know how it handles nested keys... (i.e. whether it names the element 'SiteA.Settings.RXSignalODU1' or just 'RXSignalODU1' )
And then just display the value somewhere in your html as :
{{diff}}
I'm currently rendering bootstrap modals on my webpage using MeteorJS's "renderWithData" method to load each template when it's needed.
I'm running into an issue where my helper methods which access the data in the modal using "Blaze.getData()" will occasionally return undefined and I'm unsure how to fix that.
The only way I've been able to replicate the issue is by constantly creating/destroying the modals and there doesn't seem to be anything that specifically causes the issue.
Here are the steps I've been taking:
1) I instantiate the modal with the proper data
Template.Courses.events({
'click .share-course': function (e,t) {
var courseID = $(e.target).data('courseid');
Template.instance().activeCourse.set(
createModalWithData(
{
currentInstance: Template.instance().activeCourse.get(),
template: Template.Enrollment_Generator,
dataToRender: {courseID: courseID}
}
));
$('#generateEnrollmentURL').modal('show');
}
});
Also, here is the code for "createModalWithData":
// Create a modal with a specific data context
// If modal template already exists, destroy
// and re-create with the new data context.
// If a location to render isn't specified, renders
// content in the body .
// Parameters: [Object] data { currentInstance : Template || null,
// template : Template,
// dataToRender : Object,
// (optional) location : Element
// Return: Blaze Template Instance
createModalWithData = function createModalWithData(data) {
// Ensure data exists
if (_.isUndefined(data) || _.isNull(data)) {
throw "data cannot be null or undefined";
}
// If modal already exists, destroy it
if (!_.isNull(data.currentInstance)) {
Blaze.remove(data.currentInstance);
}
// If location is undefined, set to page body
if (_.isUndefined(data.location)) {
data.location = document.body;
}
// Render modal with dataToRender
return Blaze.renderWithData(data.template,
data.dataToRender,
data.location
);
};
2) I attempt to retrieve the data using "Blaze.getData()" within my modal template
Template.Enrollment_Generator.onCreated(function() {
var courseID = Blaze.getData().courseID; // Occasionally undefined
Meteor.subscribe('enrollment-codes',courseID);
});
So far I've attempted to replace the "onCreated" method with "onRendered" but still had the same issue.
It turns out the issue was within the click event. I had a nested span element within my share-course button:
<small class="share-course" data-courseid="{{_id}}">
Share
<span class="glyphicon glyphicon-share"></span>
</small>
This was messing up the way I was targeting my embedded courseID
Instead of Blaze.getData(), I should have also been using Template.currentData() to retrieve the data within my template
As stated here: https://forums.meteor.com/t/blaze-getdata-question/5688
Below I have a basic template that has a numerical input form. When you type a number in the form and click Add a list of Divs get created. The Divs are created with a class of "synth" and an id of "synth" + a number. The numbers go in succession based on a counter.
I want to not only store this information in the database but do so in a manner that (eventually) when a user logs in they will have access to their list of Divs as a "saved state" from their previous log in.
I am not even sure if I am going about this in an appropriate manner. I am simply sticking the createSynth() function in the Collection insert for lists. I have a feeling to do this "correctly" I should have two events that work in parallel - one sending to the lists Collection and the other to the dom/Template. These two blocks would then exchange data (some how) which in conjunction create the illusion of a "saved state".
Below is the code I have thus far.
HTML
<head>
<title></title>
</head>
<body>
{{> start}}
</body>
<template name="start">
<input id ="amount" type ="number" />
<input id ="submit" type="button" value="Add" />
<div id="applicationArea"></div>
</template>
Javascript
var lists = new Meteor.Collection("Lists");
var counter = 0;
counterSynth = 0;
if (Meteor.isClient) {
'use strict';
Template.start.events({
'mousedown #submit' : function () {
var amount = document.getElementById("amount").value;
for(i=0;i<amount;i++) {
lists.insert({SoundCircle:createSynth()}); // I am inserting the entire function call, is this the right path?
}
function createSynth() {
var synth = document.createElement("div");
synth.className = "synth";
synth.id = "synth" + (counterSynth++);
applicationArea.appendChild(synth);
};
},
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
You have to use a slightly different approach to this, basically just insert your stuff into the collection, and use handlebars to get it out. I'm not entirely sure what you were doing but you should get a good idea with the below
Server js
synths = new Meteor.Collection('synths'); //This will store our synths
Client js:
synths = new Meteor.Collection('synths'); //This will store our synths
Template.start.events({
'mousedown #submit' : function () {
var amount = document.getElementById("amount").value;
for(i=0;i<amount;i++) {
lists.insert({class:"synth", id:counterSynth});
}
},
});
Template.start.synth = function() {
return synths.find(); //This gives data to the html below
}
HTML:
{{#each synth}}
<div class="{{class}}" id="synth{{id}}">
Synth stuff here
</div>
{{/each}
It's probably best to dynamically recreate the DIVs every time you need them on the client, so the DIV is not stored on the server. If you really want to hard code/store the DIV on the server you would need to simply save the HTML as a string, to a Meteor collection.